diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9fdebf90f..020fdc6ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -294,4 +294,42 @@
## Others
-* Chrome-Launcher: Open all example.com URLs with CDP and multi-tab on. https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/560
\ No newline at end of file
+* Chrome-Launcher: Open all example.com URLs with CDP and multi-tab on. https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/560
+
+
+#v0.7.0
+
+## Extension
+* Feature: Export report in an HTML file https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/545
+* Feature: Show exempted cookies in extension https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/522
+* Feature: Add i18n module https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/575
+* Feature: Accept GDPR banner consent. https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/372
+* Fix: Left over references and make some more space in the cookie table https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/584
+* Fix: Clear cookie preview area https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/568
+* Refactor: Update table storage and prefix icon type https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/546
+* Refactor: Extension UI and Service Worker. https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/519
+* Refactor: Rename column cookie affected column to issues https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/580
+* Refactor: Add disabled state to the Button component https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/585
+* Refactor: Increase test coverage for extension package https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/520
+* Refactor: Restructure cookies landing page https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/528
+* Enhancement: Add information on how to verify if a user is part of 1% experimental group https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/543
+* Enhancement:Update extension icons https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/583
+* Enhancement: Enlarge extension icon https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/598
+* Enhancement : Add blocking status column in the CSV export from the table in extension https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/591
+* Enhancement: Add context provider to sidebar https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/498
+* Miscellaneous UI updates https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/599
+* Enhancement: Navigate to `Settings` page from `Blocked Cookies` section https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/603
+* Enhancement: Use the warning icon on the cookie issues panel https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/604
+* Refactor: Update cookies section on the landing page https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/615
+* Fix: Context invalidated for sites which do not send request after the site is loaded. https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/611
+
+## CLI
+* Feature: Add option to pass a port for development server https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/579
+* Enhancement: Move download report button in cli-dashboard to the sticky menu bar https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/595
+* Enhancement: CLI, replace "Cookies with issues" with "Cookie issues" in the sidebar. https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/596
+* Enhancement: CLI updates https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/602
+* Fix: CLI dashboard showing multiple cookie entries for same cookies https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/597
+* Fix: CLI dashboard blocking reason. https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/618
+
+## Others
+* Add demo RWS for command line launcher https://github.com/GoogleChromeLabs/ps-analysis-tool/pull/578
\ No newline at end of file
diff --git a/assets/data/open-cookie-database.json b/assets/data/open-cookie-database.json
index d14760b73..77270694d 100644
--- a/assets/data/open-cookie-database.json
+++ b/assets/data/open-cookie-database.json
@@ -3013,6 +3013,19 @@
"wildcard": "0"
}
],
+ "esctx-*": [
+ {
+ "platform": "Microsoft",
+ "category": "Functional",
+ "name": "esctx-*",
+ "domain": ".login.microsoftonline.com",
+ "description": "This cookie is set by Microsoft for secure authentication of the users' login details",
+ "retention": "session",
+ "dataController": "Microsoft",
+ "gdprUrl": "https://account.microsoft.com/privacy",
+ "wildcard": "1"
+ }
+ ],
"ASP.NET_SessionId": [
{
"platform": "ASP.net",
@@ -3852,7 +3865,7 @@
"description": "Hotjar cookie. This cookie is set when the customer first lands on a page with the Hotjar script. It is used to persist the random user ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3865,7 +3878,7 @@
"description": "Hotjar cookie. This session cookie is set to let Hotjar know whether that visitor is included in the sample which is used to generate funnels.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3878,7 +3891,7 @@
"description": "Hotjar cookie. This cookie is set once a visitor interacts with a Survey invitation modal popup. It is used to ensure that the same invite does not re-appear if it has already been shown.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3891,7 +3904,7 @@
"description": "Hotjar cookie. This cookie is set once a visitor completes a poll using the Feedback Poll widget. It is used to ensure that the same poll does not re-appear if it has already been filled in.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3904,7 +3917,7 @@
"description": "Hotjar cookie. This cookie is set once a visitor minimizes a Feedback Poll widget. It is used to ensure that the widget stays minimizes when the visitor navigates through your site.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3917,7 +3930,7 @@
"description": "Hotjar cookie. This cookie is set once a visitor submits their information in the Recruit User Testers widget. It is used to ensure that the same form does not re-appear if it has already been filled in.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3930,7 +3943,7 @@
"description": "Hotjar cookie. This cookie is set once a visitor minimizes a Recruit User Testers widget. It is used to ensure that the widget stays minimizes when the visitor navigates through your site.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3943,7 +3956,7 @@
"description": "This cookie is set when a visitor minimizes or completes Incoming Feedback. This is done so that the Incoming Feedback will load as minimized immediately if they navigate to another page where it is set to show.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3956,7 +3969,7 @@
"description": "When the Hotjar script executes we try to determine the most generic cookie path we should use, instead of the page hostname. This is done so that cookies can be shared across subdomains (where applicable). To determine this, we try to store the _hjTLDTest cookie for different URL substring alternatives until it fails. After this check, the cookie is removed.",
"retention": "session",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3969,7 +3982,7 @@
"description": "User Attributes sent through the Hotjar Identify API are cached for the duration of the session in order to know when an attribute has changed and needs to be updated.",
"retention": "session",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3982,7 +3995,7 @@
"description": "This cookie stores User Attributes which are sent through the Hotjar Identify API, whenever the user is not in the sample. These attributes will only be saved if the user interacts with a Hotjar Feedback tool.",
"retention": "session",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -3995,7 +4008,7 @@
"description": "This cookie is used to check if the Hotjar Tracking Script can use local storage. If it can, a value of 1 is set in this cookie. The data stored in_hjLocalStorageTest has no expiration time, but it is deleted immediately after creating it so the expected storage time is under 100ms.",
"retention": "",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -4008,7 +4021,7 @@
"description": "This cookie is set for logged in users of Hotjar, who have Admin Team Member permissions. It is used during pricing experiments to show the Admin consistent pricing across the site.",
"retention": "session",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -4021,7 +4034,7 @@
"description": "The cookie is set so Hotjar can track the beginning of the user's journey for a total session count. It does not contain any identifiable information.",
"retention": "30 minutes",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -4034,7 +4047,7 @@
"description": "The cookie is set so Hotjar can track the beginning of the user's journey for a total session count. It does not contain any identifiable information.",
"retention": "30 minutes",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -4047,7 +4060,7 @@
"description": "This cookie is set to let Hotjar know whether that visitor is included in the data sampling defined by your site's page view limit.",
"retention": "30 minutes",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -4060,7 +4073,7 @@
"description": "This cookie is set to let Hotjar know whether that visitor is included in the data sampling defined by your site's daily session limit",
"retention": "30 minutes",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "1"
}
],
@@ -4073,7 +4086,7 @@
"description": "A cookie that holds the current session data. This ensues that subsequent requests within the session window will be attributed to the same Hotjar session.",
"retention": "30 minutes",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "1"
}
],
@@ -4086,7 +4099,7 @@
"description": "Hotjar cookie that is set when a user first lands on a page with the Hotjar script. It is used to persist the Hotjar User ID, unique to that site on the browser. This ensures that behavior in subsequent visits to the same site will be attributed to the same user ID.",
"retention": "365 days",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "1"
}
],
@@ -4099,7 +4112,7 @@
"description": "Causes Hotjar to stop collecting data if a session becomes too large. This is determined automatically by a signal from the WebSocket server if the session size exceeds the limit.",
"retention": "session",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -4112,7 +4125,7 @@
"description": "If present, this cookie will be set to 1 for the duration of a user’s session, if Hotjar rejected the session from connecting to our WebSocket due to server overload. This cookie is only applied in extremely rare situations to prevent severe performance issues.",
"retention": "session",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -4125,7 +4138,7 @@
"description": "A cookie that is set when a session/recording is reconnected to Hotjar servers after a break in connection.",
"retention": "session",
"dataController": "Hotjar",
- "gdprUrl": "https://www.hotjar.com/legal/compliance/opt-out",
+ "gdprUrl": "https://www.hotjar.com/legal/policies/privacy/",
"wildcard": "0"
}
],
@@ -5564,7 +5577,7 @@
"platform": "ComScore",
"category": "Marketing",
"name": "UIDR",
- "domain": "scorecardresearch.com",
+ "domain": ".scorecardresearch.com",
"description": "Collects information of the user and his/her movement, such as timestamp for visits, most recently loaded pages and IP address. The data is used by the marketing research network, Scorecard Research, to analyse traffic patterns and carry out surveys to help their clients better understand the customer's preferences.",
"retention": "2 years",
"dataController": "ComScore",
@@ -5585,6 +5598,32 @@
"wildcard": "0"
}
],
+ "PID": [
+ {
+ "platform": "ComScore",
+ "category": "Marketing",
+ "name": "PID",
+ "domain": ".scorecardresearch.com",
+ "description": "Collects a code that identifies the specific website or advertiser participating in the ScorecardResearch data collection program.",
+ "retention": "1 year",
+ "dataController": "ComScore",
+ "gdprUrl": "https://www.comscore.com/About/Privacy-Policy",
+ "wildcard": "0"
+ }
+ ],
+ "XID": [
+ {
+ "platform": "ComScore",
+ "category": "Marketing",
+ "name": "XID",
+ "domain": ".scorecardresearch.com",
+ "description": "Collects a unique identifier assigned to a device (computer, phone, tablet) to track the user across different websites.",
+ "retention": "1 year",
+ "dataController": "ComScore",
+ "gdprUrl": "https://www.comscore.com/About/Privacy-Policy",
+ "wildcard": "0"
+ }
+ ],
"SEUNCY": [
{
"platform": "semasio.net",
@@ -5923,27 +5962,79 @@
],
"st_csd": [
{
- "platform": "seedtag.com",
+ "platform": "Seedtag",
"category": "Marketing",
"name": "st_csd",
"domain": "seedtag.com",
"description": "Date of the last cookie-syn",
"retention": "1 year",
"dataController": "seedtag.com",
- "gdprUrl": "",
+ "gdprUrl": "https://www.seedtag.com/privacy/",
"wildcard": "0"
}
],
"st_cs": [
{
- "platform": "seedtag.com",
+ "platform": "Seedtag",
"category": "Marketing",
"name": "st_cs",
"domain": "seedtag.com",
"description": "Unique identifiers of DSPs",
"retention": "1 year",
"dataController": "seedtag.com",
- "gdprUrl": "",
+ "gdprUrl": "https://www.seedtag.com/privacy/",
+ "wildcard": "0"
+ }
+ ],
+ "st_uid": [
+ {
+ "platform": "Seedtag",
+ "category": "Marketing",
+ "name": "st_uid",
+ "domain": "seedtag.com",
+ "description": "This cookie is used to store randomly generated unique browser identifier",
+ "retention": "1 year",
+ "dataController": "seedtag.com",
+ "gdprUrl": "https://www.seedtag.com/privacy/",
+ "wildcard": "0"
+ }
+ ],
+ "st_cnt": [
+ {
+ "platform": "Seedtag",
+ "category": "Marketing",
+ "name": "st_cnt",
+ "domain": "seedtag.com",
+ "description": "This cookie is used to store low precision geolocation (Country, City)",
+ "retention": "1 year",
+ "dataController": "seedtag.com",
+ "gdprUrl": "https://www.seedtag.com/privacy/",
+ "wildcard": "0"
+ }
+ ],
+ "st_chc": [
+ {
+ "platform": "Seedtag",
+ "category": "Marketing",
+ "name": "st_chc",
+ "domain": "seedtag.com",
+ "description": "This cookie is used to store Cookie-sync",
+ "retention": "1 year",
+ "dataController": "seedtag.com",
+ "gdprUrl": "https://www.seedtag.com/privacy/",
+ "wildcard": "0"
+ }
+ ],
+ "st_ssp": [
+ {
+ "platform": "Seedtag",
+ "category": "Marketing",
+ "name": "st_ssp",
+ "domain": "seedtag.com",
+ "description": "This cookie is used to store low precision geolocation",
+ "retention": "1 year",
+ "dataController": "seedtag.com",
+ "gdprUrl": "https://www.seedtag.com/privacy/",
"wildcard": "0"
}
],
@@ -6266,7 +6357,46 @@
"description": "This cookie is used to identify the visitor and optimize ad-relevance by collecting visitor data from multiple websites – this exchange of visitor data is normally provided by a third-party data-center or ad-exchange.",
"retention": "3 months",
"dataController": "TripleLift",
- "gdprUrl": "",
+ "gdprUrl": "https://triplelift.com/advertising-technology-platform-cookie-notice/",
+ "wildcard": "0"
+ }
+ ],
+ "tluidp": [
+ {
+ "platform": "TripleLift",
+ "category": "Marketing",
+ "name": "tluidp",
+ "domain": "3lift.com",
+ "description": "This cookie is used to identify the visitor and optimize ad-relevance by collecting visitor data from multiple websites with – this exchange of visitor data is normally provided by a third-party data-center or ad-exchange.",
+ "retention": "3 months",
+ "dataController": "TripleLift",
+ "gdprUrl": "https://triplelift.com/advertising-technology-platform-cookie-notice/",
+ "wildcard": "0"
+ }
+ ],
+ "optout": [
+ {
+ "platform": "TripleLift",
+ "category": "Marketing",
+ "name": "optout",
+ "domain": "3lift.com",
+ "description": "This cookie is used to determine whether the visitor has accepted the cookie consent box.",
+ "retention": "5 years",
+ "dataController": "TripleLift",
+ "gdprUrl": "https://triplelift.com/advertising-technology-platform-cookie-notice/",
+ "wildcard": "0"
+ }
+ ],
+ "sync": [
+ {
+ "platform": "TripleLift",
+ "category": "Marketing",
+ "name": "sync",
+ "domain": "3lift.com",
+ "description": "This cookie is used in order to transact in digital advertising, TripleLift exchanges (or syncs) identifiers with other companies. This cookie keeps track of which companies have recently been synced in order to avoid syncing with the same companies repetitively.",
+ "retention": "3 months",
+ "dataController": "TripleLift",
+ "gdprUrl": "https://triplelift.com/advertising-technology-platform-cookie-notice/",
"wildcard": "0"
}
],
@@ -6276,7 +6406,7 @@
"category": "Marketing",
"name": "t_gid",
"domain": "taboola.com",
- "description": "This cookie gives a user who interacts with Taboola Widget a User ID allowing us to target advertisements and content to this specific user ID.",
+ "description": "This Partitioned cookie gives a user who interacts with Taboola Widget a User ID allowing us to target advertisements and content to this specific user ID.",
"retention": "13 months",
"dataController": "taboola.com",
"gdprUrl": "",
@@ -7091,14 +7221,235 @@
],
"everest_g_v2": [
{
- "platform": "Everest Technologies",
+ "platform": "Adobe Advertising",
"category": "Marketing",
"name": "everest_g_v2",
"domain": "everesttech.net",
- "description": "Created after a user initially clicks a client's ad, and used to map the current and subsequent clicks with other events on the client's website",
+ "description": "This cookie stores the browser and surfer ID.Created after a user initially clicks a client's ad, and used to map the current and subsequent clicks with other events on the client's website",
"retention": "2 years",
- "dataController": "Everest Technologies",
- "gdprUrl": "",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "everest_session_v2": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "everest_session_v2",
+ "domain": "everesttech.net",
+ "description": "This cookie stores the session ID",
+ "retention": "session",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_tm": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_tm",
+ "domain": "everesttech.net",
+ "description": "This cookie stores the Adobe Advertising DSP (Demand Side Platform) ID. \tA third-party cookie that stores the DSP ID that corresponds to the surfer ID in the everest_g_v2 cookie",
+ "retention": "2 years",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "_tmae": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "_tmae",
+ "domain": "everesttech.net",
+ "description": "This cookie stores Encoded IDs and time stamps for ad engagements using Adobe Advertising DSP tracking.A third-party cookie that stores user engagements with ads, such as 'last seen ad xyz123 on June 30, 2016'",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "_lcc": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "_lcc",
+ "domain": "everesttech.net",
+ "description": "This cookie stores IDs and time stamps (in the format yyyymmdd) of display clicks. It is a third-party cookie used to determine if a click event on a display ad applies to an Adobe Analytics hit",
+ "retention": "15 minutes",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_ax": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_ax",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_bk": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_bk",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_dd": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_dd",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_fs": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_fs",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_ix": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_ix",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_nx": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_nx",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_ox": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_ox",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_pm": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_pm",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_rc": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_rc",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_tm": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_tm",
+ "domain": "everesttech.net",
+ "description": "This cookie stores The date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "ev_sync_yh": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "ev_sync_yh",
+ "domain": "everesttech.net",
+ "description": "This cookie stores the date when synchronization is performed, in the format yyyymmdd. A third-party, ad exchange-specific cookie that syncs the Adobe Advertising surfer ID with the partner ad exchange. It's created for new surfers and sends a synchronization request when it's expired.",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "adcloud": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "adcloud",
+ "domain": "",
+ "description": "This cookie stores The timestamps of the surfer's last visit to the advertiser’s website and the surfer's last search click, and the ef_id that was created when the user clicked an ad",
+ "retention": "1 year",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
+ "id_adcloud": [
+ {
+ "platform": "Adobe Advertising",
+ "category": "Marketing",
+ "name": "id_adcloud",
+ "domain": "",
+ "description": "This cookie stores the surfer ID",
+ "retention": "91 days",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
"wildcard": "0"
}
],
@@ -7280,7 +7631,59 @@
"description": "Registers data on visitors from multiple visits and on multiple websites. This information is used to measure the efficiency of advertisement on websites.",
"retention": "10 years",
"dataController": "Zeotap",
- "gdprUrl": "https://www.zeotap.com/privacy_policy",
+ "gdprUrl": "https://zeotap.com/product-privacy-policy/",
+ "wildcard": "0"
+ }
+ ],
+ "zsc": [
+ {
+ "platform": "Zeotap",
+ "category": "Marketing",
+ "name": "zsc",
+ "domain": "zeotap.com",
+ "description": "Frequency capping for cookie syncing",
+ "retention": "1 day",
+ "dataController": "Zeotap",
+ "gdprUrl": "https://zeotap.com/product-privacy-policy/",
+ "wildcard": "0"
+ }
+ ],
+ "zi": [
+ {
+ "platform": "Zeotap",
+ "category": "Marketing",
+ "name": "zi",
+ "domain": "zeotap.com",
+ "description": "User Identification",
+ "retention": "1 year",
+ "dataController": "Zeotap",
+ "gdprUrl": "https://zeotap.com/product-privacy-policy/",
+ "wildcard": "0"
+ }
+ ],
+ "idp": [
+ {
+ "platform": "Zeotap",
+ "category": "Marketing",
+ "name": "idp",
+ "domain": "zeotap.com",
+ "description": "User Identification",
+ "retention": "1 year",
+ "dataController": "Zeotap",
+ "gdprUrl": "https://zeotap.com/product-privacy-policy/",
+ "wildcard": "0"
+ }
+ ],
+ "zuc": [
+ {
+ "platform": "Zeotap",
+ "category": "Marketing",
+ "name": "zuc",
+ "domain": "zeotap.com",
+ "description": "User Identification",
+ "retention": "1 year",
+ "dataController": "Zeotap",
+ "gdprUrl": "https://zeotap.com/product-privacy-policy/",
"wildcard": "0"
}
],
@@ -7960,6 +8363,19 @@
"wildcard": "0"
}
],
+ "login_redirect": [
+ {
+ "platform": "Magento",
+ "category": "Functional",
+ "name": "login_redirect",
+ "domain": "",
+ "description": "Preserves the destination page that was loading before the customer was directed to log in.",
+ "retention": "session",
+ "dataController": "Adobe",
+ "gdprUrl": "https://www.adobe.com/privacy.html",
+ "wildcard": "0"
+ }
+ ],
"dsps:*": [
{
"platform": "PowerLinks Media Limited",
@@ -9269,6 +9685,45 @@
"wildcard": "0"
}
],
+ "hubspotapi": [
+ {
+ "platform": "Hubspot",
+ "category": "Marketing",
+ "name": "hubspotapi",
+ "domain": "hubspot.com",
+ "description": "This cookie allows the user to access the app with the correct permissions.",
+ "retention": "7 days",
+ "dataController": "HubSpot",
+ "gdprUrl": "https://legal.hubspot.com/privacy-policy",
+ "wildcard": "0"
+ }
+ ],
+ "hubspotapi-prefs": [
+ {
+ "platform": "Hubspot",
+ "category": "Functional",
+ "name": "hubspotapi-prefs",
+ "domain": "hubspot.com",
+ "description": "This is used with the hubspotapi cookie to remember whether the user checked the 'remember me' box (controls the expiration of the main cookie's authentication).",
+ "retention": "1 Year",
+ "dataController": "HubSpot",
+ "gdprUrl": "https://legal.hubspot.com/privacy-policy",
+ "wildcard": "0"
+ }
+ ],
+ "hubspotapi-csrf": [
+ {
+ "platform": "Hubspot",
+ "category": "Functional",
+ "name": "hubspotapi-csrf",
+ "domain": "hubspot.com",
+ "description": "This is used for CSRF prevention - preventing third party websites from accessing your data. Expires after a year.",
+ "retention": "1 year",
+ "dataController": "HubSpot",
+ "gdprUrl": "https://legal.hubspot.com/privacy-policy",
+ "wildcard": "0"
+ }
+ ],
"vuid": [
{
"platform": "Vimeo",
@@ -11657,7 +12112,7 @@
"description": "Unique identifier for the BlueConic profile.",
"retention": "1 year",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -11670,7 +12125,7 @@
"description": "Temporary unique identifier for the BlueConic profile, removed after BCSessionID is created.",
"retention": "10 minutes",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -11683,7 +12138,7 @@
"description": "Opt-in level (PERSONAL|ANONYMOUS|DO_NOT_TRACK)",
"retention": "1 year",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -11696,7 +12151,7 @@
"description": "Stores a custom bcChannelIdentifier as referrer. For these channels the actual referrer points to the website and not the overrule. The overrule would be lost if not stored in this cookie.",
"retention": "1 year",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -11709,7 +12164,7 @@
"description": "Used to store the identifiers of BlueConic Objectives that were explicitly refused.",
"retention": "1 year",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -11722,7 +12177,7 @@
"description": "Used to store requests that are sent to BlueConic, but haven't returned yet. On the next page view, if BCRevision still contains values, those requests are sent again, to prevent data loss. This information is now stored in localStorage; when this fails, the cookie solution is used as fallback.",
"retention": "1 year",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -11735,7 +12190,7 @@
"description": "Used for tracking the channel of an external tracker.",
"retention": "10 seconds",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -11748,7 +12203,7 @@
"description": "Gathers information on the user’s behavior, preferences and other personal data, which is sent to a third-party marketing and analysis service, for optimization of the website’s advertisement, analysis and general traffic.",
"retention": "1 year",
"dataController": "Blueconic.com",
- "gdprUrl": "https://www.blueconic.com/privacy-policy/",
+ "gdprUrl": "https://www.blueconic.com/privacy-policy",
"wildcard": "0"
}
],
@@ -17998,7 +18453,7 @@
"category": "Functional",
"name": "__pid",
"domain": "",
- "description": "This cookie store the domain received on the frontend is used as a domain for other cookies (incl. __utp, __idr, __tae) Example value: .piano.io",
+ "description": "This cookie stores the domain received on the frontend is used as a domain for other cookies (incl. __utp, __idr, __tae) Example value: .piano.io",
"retention": "30 days",
"dataController": "Piano",
"gdprUrl": "https://piano.io/privacy-policy/",
@@ -18076,7 +18531,7 @@
"category": "Analytics",
"name": "__pvi",
"domain": "",
- "description": "This cookie store data about the last visit to the site including the AID, lastTrackedVisitId, domain and time of the visit. Used for reporting only.",
+ "description": "This cookie stores data about the last visit to the site including the AID, lastTrackedVisitId, domain and time of the visit. Used for reporting only.",
"retention": "1 day",
"dataController": "Piano",
"gdprUrl": "https://piano.io/privacy-policy/",
@@ -18089,7 +18544,7 @@
"category": "Analytics",
"name": "__pat",
"domain": "",
- "description": "This cookie store difference between the client’s application time zone and UTC. At midnight, (application's local time), the previous visit is expired and a new one is created. The cookie is used for calculation.",
+ "description": "This cookie stores difference between the client’s application time zone and UTC. At midnight, (application's local time), the previous visit is expired and a new one is created. The cookie is used for calculation.",
"retention": "30 days",
"dataController": "Piano",
"gdprUrl": "https://piano.io/privacy-policy/",
@@ -18102,7 +18557,7 @@
"category": "Functional",
"name": "__pnahc",
"domain": "",
- "description": "This cookie store the result of previous Adblock detection, removes false-positive AdBlock detection clauses.",
+ "description": "This cookie stores the result of previous Adblock detection, removes false-positive AdBlock detection clauses.",
"retention": "90 days",
"dataController": "Piano",
"gdprUrl": "https://piano.io/privacy-policy/",
@@ -18115,7 +18570,7 @@
"category": "Functional",
"name": "LANG",
"domain": "tinypass.com",
- "description": "This cookie store the selected locale",
+ "description": "This cookie stores the selected locale",
"retention": "1500 days",
"dataController": "Piano",
"gdprUrl": "https://piano.io/privacy-policy/",
@@ -18128,7 +18583,7 @@
"category": "Functional",
"name": "LANG_CHANGED",
"domain": "tinypass.com",
- "description": "This cookie store the temporarily selected locale (e.g. impersonation in Admin dashboard).",
+ "description": "This cookie stores the temporarily selected locale (e.g. impersonation in Admin dashboard).",
"retention": "1 day",
"dataController": "Piano",
"gdprUrl": "https://piano.io/privacy-policy/",
@@ -18732,5 +19187,304 @@
"gdprUrl": "https://www.emetriq.com/datenschutz/",
"wildcard": "0"
}
+ ],
+ "_pangle": [
+ {
+ "platform": "Pangle",
+ "category": "Marketing",
+ "name": "_pangle",
+ "domain": "analytics.pangle-ads.com",
+ "description": "This cookie is to measure and improve the performance of your advertising campaigns and to personalize the user's ad experiences delivered by the Pangle ad network.",
+ "retention": "13 months",
+ "dataController": "Pangle",
+ "gdprUrl": "https://www.pangleglobal.com/privacy",
+ "wildcard": "0"
+ }
+ ],
+ "u": [
+ {
+ "platform": "Totvs",
+ "category": "Marketing",
+ "name": "u",
+ "domain": "t.tailtarget.com",
+ "description": "This cookie is Used for audience segmentation for advertising",
+ "retention": "1 year",
+ "dataController": "Totvs",
+ "gdprUrl": "https://www.totvs.com/protecao-e-privacidade-de-dados/",
+ "wildcard": "0"
+ }
+ ],
+ "_ssc": [
+ {
+ "platform": "Totvs",
+ "category": "Marketing",
+ "name": "_ssc",
+ "domain": "t.tailtarget.com",
+ "description": "This is a cookie used for generating access and internet traffic statistics.",
+ "retention": "1 day",
+ "dataController": "Totvs",
+ "gdprUrl": "https://www.totvs.com/protecao-e-privacidade-de-dados/",
+ "wildcard": "0"
+ }
+ ],
+ "NSC_*": [
+ {
+ "platform": "Citrix",
+ "category": "Functional",
+ "name": "NSC_*",
+ "domain": "",
+ "description": "This cookie name is associated with the Netscaler load balancing service from Citrix. This is a pattern type cookie with the root being NSC_ and the rest of the name being a unique encrypted alpha numeric identifier for the virtual server it originated from. The cookie is used to ensure traffic and user data is routed to the correct locations where a site is hosted on multiple servers, so that the end user has a consistent experience.",
+ "retention": "12 hours",
+ "dataController": "Citrix",
+ "gdprUrl": "https://www.citrix.com/about/trust-center/privacy-compliance/",
+ "wildcard": "1"
+ }
+ ],
+ "bitoIsSecure": [
+ {
+ "platform": "Beeswax",
+ "category": "Marketing",
+ "name": "bitoIsSecure",
+ "domain": "bidr.io",
+ "description": "This cookie is associated with bidr.io. It allows third party advertisers to target the visitor with relevant advertising. This pairing service is provided by third party advertisement hubs, which facilitate real-time bidding for advertisers.",
+ "retention": "1 year",
+ "dataController": "Beeswax",
+ "gdprUrl": "https://www.beeswax.com/privacy/",
+ "wildcard": "0"
+ }
+ ],
+ "bito": [
+ {
+ "platform": "Beeswax",
+ "category": "Marketing",
+ "name": "bito",
+ "domain": "bidr.io",
+ "description": "This cookie is generally provided by bidr.io and is used for advertising purposes.",
+ "retention": "1 year",
+ "dataController": "Beeswax",
+ "gdprUrl": "https://www.beeswax.com/privacy/",
+ "wildcard": "0"
+ }
+ ],
+ "WMF-Last-Access": [
+ {
+ "platform": "Wikimedia",
+ "category": "Analytics",
+ "name": "WMF-Last-Access",
+ "domain": ".wikimedia.org",
+ "description": "This cookie is used by the Wikimedia Foundation. It is used to determine the last time a user visited a page, and is used for various statistics.",
+ "retention": "session",
+ "dataController": "Wikipedia",
+ "gdprUrl": "https://foundation.wikimedia.org/wiki/Policy:Privacy_policy",
+ "wildcard": "0"
+ }
+ ],
+ "loginnotify_prevlogins": [
+ {
+ "platform": "Wikimedia",
+ "category": "Functional",
+ "name": "loginnotify_prevlogins",
+ "domain": ".wikimedia.org",
+ "description": "This cookie verifies that you are logging in from a known device. This affects the threshold for how many unsuccessful login attempts trigger a notification to the user..",
+ "retention": "180 days",
+ "dataController": "Wikipedia",
+ "gdprUrl": "https://foundation.wikimedia.org/wiki/Policy:Privacy_policy",
+ "wildcard": "0"
+ }
+ ],
+ "stopMobileRedirect": [
+ {
+ "platform": "Wikimedia",
+ "category": "Functional",
+ "name": "stopMobileRedirect",
+ "domain": ".wikimedia.org",
+ "description": "This cookie tells us not to redirect to the mobile site if you do not like that..",
+ "retention": "30 days",
+ "dataController": "Wikipedia",
+ "gdprUrl": "https://foundation.wikimedia.org/wiki/Policy:Privacy_policy",
+ "wildcard": "0"
+ }
+ ],
+ "centralnotice_bucket": [
+ {
+ "platform": "Wikimedia",
+ "category": "Analytics",
+ "name": "centralnotice_bucket",
+ "domain": ".wikimedia.org",
+ "description": "This cookie helps us understand the effectiveness of notices provided to users through the CentralNotice extension..",
+ "retention": "session",
+ "dataController": "Wikipedia",
+ "gdprUrl": "https://foundation.wikimedia.org/wiki/Policy:Privacy_policy",
+ "wildcard": "0"
+ }
+ ],
+ "GeoIP": [
+ {
+ "platform": "Wikimedia",
+ "category": "Analytics",
+ "name": "GeoIP",
+ "domain": ".wikimedia.org",
+ "description": "This cookie is used to try and understand the user's geographical location (country) based on their IP address.",
+ "retention": "session",
+ "dataController": "Wikipedia",
+ "gdprUrl": "https://foundation.wikimedia.org/wiki/Policy:Privacy_policy",
+ "wildcard": "0"
+ }
+ ],
+ "NetWorkProbeLimit": [
+ {
+ "platform": "Wikimedia",
+ "category": "Analytics",
+ "name": "NetWorkProbeLimit",
+ "domain": ".wikimedia.org",
+ "description": "This cookie is used to set NetworkProbeLimit cookie to override the default network probe limit value.",
+ "retention": "1 hour",
+ "dataController": "Wikipedia",
+ "gdprUrl": "https://foundation.wikimedia.org/wiki/Policy:Privacy_policy",
+ "wildcard": "0"
+ }
+ ],
+ "auid": [
+ {
+ "platform": "Acuity",
+ "category": "Marketing",
+ "name": "auid",
+ "domain": ".acuityplatform.com",
+ "description": "This cookie is used to identify the visitor and cookie-tracking solutions and marketing and advertising services..",
+ "retention": "1 year",
+ "dataController": "Acuity",
+ "gdprUrl": "",
+ "wildcard": "0"
+ }
+ ],
+ "aum": [
+ {
+ "platform": "Acuity",
+ "category": "Marketing",
+ "name": "aum",
+ "domain": ".acuityplatform.com",
+ "description": "This cookie is used to identify the visitor and the company provides a range of cookie-tracking solutions and marketing and advertising services.",
+ "retention": "1 year",
+ "dataController": "Acuity",
+ "gdprUrl": "",
+ "wildcard": "0"
+ }
+ ],
+ "ablyft_exps": [
+ {
+ "platform": "ABlyft",
+ "category": "Analytics",
+ "name": "ablyft_exps",
+ "domain": "",
+ "description": "Is set and updated when a visitor is bucketed into an experiment/variation.",
+ "retention": "1 year",
+ "dataController": "ABlyft",
+ "gdprUrl": "https://ablyft.com/en/privacy-notice",
+ "wildcard": "0"
+ }
+ ],
+ "ablyft_queue": [
+ {
+ "platform": "ABlyft",
+ "category": "Analytics",
+ "name": "ablyft_queue",
+ "domain": "",
+ "description": "Is set when a visitor triggers an event/goal. After sending the event to ABlyft it is cleared.",
+ "retention": "1 year",
+ "dataController": "ABlyft",
+ "gdprUrl": "https://ablyft.com/en/privacy-notice",
+ "wildcard": "0"
+ }
+ ],
+ "ablyft_uvs": [
+ {
+ "platform": "ABlyft",
+ "category": "Analytics",
+ "name": "ablyft_uvs",
+ "domain": "",
+ "description": "Is set on the first pageview and update with every further pageview of a visitor.",
+ "retention": "1 year",
+ "dataController": "ABlyft",
+ "gdprUrl": "https://ablyft.com/en/privacy-notice",
+ "wildcard": "0"
+ }
+ ],
+ "ablyft_tracking_consent": [
+ {
+ "platform": "ABlyft",
+ "category": "Analytics",
+ "name": "ablyft_tracking_consent",
+ "domain": "",
+ "description": "Is set when enableTrackingConsent or disableTrackingConsent is triggered via API.",
+ "retention": "1 year",
+ "dataController": "ABlyft",
+ "gdprUrl": "https://ablyft.com/en/privacy-notice",
+ "wildcard": "0"
+ }
+ ],
+ "_d2id": [
+ {
+ "platform": "MercadoLibre",
+ "category": "Marketing",
+ "name": "_d2id",
+ "domain": ".mercadolibre.com",
+ "description": "This cookie is required for shopping cart functionality on the website.",
+ "retention": "1 year",
+ "dataController": "MercadoLibre",
+ "gdprUrl": "https://www.mercadolibre.com.ar/privacidad",
+ "wildcard": "0"
+ }
+ ],
+ "edsid": [
+ {
+ "platform": "MercadoLibre",
+ "category": "Marketing",
+ "name": "edsid",
+ "domain": ".mercadolibre.com",
+ "description": "This cookie is used to identify users to implement fraud prevention",
+ "retention": "1 year",
+ "dataController": "MercadoLibre",
+ "gdprUrl": "https://www.mercadolibre.com.ar/privacidad",
+ "wildcard": ""
+ }
+ ],
+ "ftid": [
+ {
+ "platform": "MercadoLibre",
+ "category": "Marketing",
+ "name": "ftid",
+ "domain": ".mercadolibre.com",
+ "description": "This cookie is used to identify users to implement fraud prevention",
+ "retention": "1 year",
+ "dataController": "MercadoLibre",
+ "gdprUrl": "https://www.mercadolibre.com.ar/privacidad",
+ "wildcard": "0"
+ }
+ ],
+ "aniC": [
+ {
+ "platform": "Aniview",
+ "category": "Marketing",
+ "name": "aniC",
+ "domain": ".aniview.com",
+ "description": "This cookie is used in context with video-advertisement. The cookie limits the number of times a user is shown the same advertisement. The cookie is also used to ensure relevance of the video-advertisement to the specific user.",
+ "retention": "20 Days",
+ "dataController": "Aniview",
+ "gdprUrl": "https://www.aniview.com/privacy-policy/",
+ "wildcard": "0"
+ }
+ ],
+ "version": [
+ {
+ "platform": "Anivew",
+ "category": "Marketing",
+ "name": "version",
+ "domain": "track1.aniview.com",
+ "description": "This cookie is used by the website's operator in context with multi-variate testing. This is a tool used to combine or change content on the website. This allows the website to find the best variation/edition of the site.",
+ "retention": "Session",
+ "dataController": "Aniview",
+ "gdprUrl": "https://www.aniview.com/privacy-policy/",
+ "wildcard": "0"
+ }
]
}
diff --git a/bin/chrome-3pcd-ps.bat b/bin/chrome-3pcd-ps.bat
index d04ce3ab8..ebf6c6c99 100644
--- a/bin/chrome-3pcd-ps.bat
+++ b/bin/chrome-3pcd-ps.bat
@@ -1,7 +1,7 @@
:: Chrome 3pcd with PS Extension
:: Download PS Extension
-set "ps_analysis_tool_version=v0.6.0"
+set "ps_analysis_tool_version=v0.7.0"
cd /d %TEMP%
if not exist %TEMP%\ps-analysis-tool-%ps_analysis_tool_version% (
mkdir %TEMP%\ps-analysis-tool-%ps_analysis_tool_version%
diff --git a/bin/chrome-default-ps.bat b/bin/chrome-default-ps.bat
index 2d98b65b9..b7f03949c 100644
--- a/bin/chrome-default-ps.bat
+++ b/bin/chrome-default-ps.bat
@@ -1,7 +1,7 @@
:: Default Chrome with PS Extension
:: Download PS Extension
-set "ps_analysis_tool_version=v0.6.0"
+set "ps_analysis_tool_version=v0.7.0"
cd /d %TEMP%
if not exist %TEMP%\ps-analysis-tool-%ps_analysis_tool_version% (
mkdir %TEMP%\ps-analysis-tool-%ps_analysis_tool_version%
diff --git a/bin/chrome_launcher.sh b/bin/chrome_launcher.sh
index e5cd3610c..356dd3d5a 100644
--- a/bin/chrome_launcher.sh
+++ b/bin/chrome_launcher.sh
@@ -2,7 +2,7 @@
# Download Extension
extension_setup() {
- ps_analysis_tool_version=v0.6.0
+ ps_analysis_tool_version=v0.7.0
extension_dir="/var/tmp"
cd $extension_dir
if [ ! -d $extension_dir/ps-analysis-tool-$ps_analysis_tool_version ]; then
diff --git a/data/related_website_sets.json b/data/related_website_sets.json
index 3e34383a3..fa8da07de 100644
--- a/data/related_website_sets.json
+++ b/data/related_website_sets.json
@@ -608,6 +608,19 @@
"https://startupislandtaiwan.org": "Domain alias"
}
},
+ {
+ "contact": "k.vermote@eurofleet-consult.com",
+ "primary": "https://carcostadvisor.com",
+ "associatedSites": [],
+ "serviceSites": [],
+ "rationaleBySite": {},
+ "ccTLDs": {
+ "https://carcostadvisor.com": [
+ "https://carcostadvisor.be",
+ "https://carcostadvisor.fr"
+ ]
+ }
+ },
{
"contact": "addigital@caracoltv.com.co",
"primary": "https://caracoltv.com",
@@ -645,6 +658,36 @@
"rationaleBySite": {
"https://wordle.at": "We are migrating our domain and will soon redirect all traffic from here to the primary, both of which we own. The two sites are almost identical. For convenience we want to transfer session cookies so users stay logged in."
}
+ },
+ {
+ "primary": "https://blackrock.com",
+ "contact": "extcontactcwp@blackrock.com",
+ "associatedSites": [
+ "https://blackrockadvisorelite.it",
+ "https://cachematrix.com",
+ "https://efront.com",
+ "https://etfacademy.it",
+ "https://ishares.com"
+ ],
+ "rationaleBySite": {
+ "https://blackrockadvisorelite.it": "A site for Italian investment professionals. The branding is clearly visible on the site.",
+ "https://cachematrix.com": "Cachematrix is a cash management firm acquired by BlackRock. The relationship is described on the About Us page.",
+ "https://efront.com": "eFront is BlackRock's alternative solutions platform. The BlackRock branding is clearly visible on the site.",
+ "https://etfacademy.it": "An Italian language education site about ETFs. The iShares by BlackRock branding is clearly visible on the site.",
+ "https://ishares.com": "iShares is BlackRock's ETF brand. The branding is clearly visible on the site."
+ }
+ },
+ {
+ "contact": "ewelina.salamonik@wbd.com",
+ "primary": "https://tvn.pl",
+ "associatedSites": [
+ "https://tvn24.pl",
+ "https://zdrowietvn.pl"
+ ],
+ "rationaleBySite": {
+ "https://zdrowietvn.pl": "Educational service that is owned by TVN S.A.. Information about the connection with TVN is included in the footer of this website",
+ "https://tvn24.pl": "News service that is owned by TVN S.A.. Information about the connection with TVN is included in the footer of this website"
+ }
}
]
}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index db3abf4ee..0cc70cb30 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ps-analysis-tool",
- "version": "0.6.0",
+ "version": "0.7.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "ps-analysis-tool",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"workspaces": [
"packages/*"
@@ -94,9 +94,8 @@
},
"node_modules/@adobe/css-tools": {
"version": "4.3.2",
- "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
- "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
@@ -2290,6 +2289,50 @@
"version": "0.1.6",
"license": "MIT"
},
+ "node_modules/@formatjs/ecma402-abstract": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz",
+ "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==",
+ "dependencies": {
+ "@formatjs/intl-localematcher": "0.5.4",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/fast-memoize": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
+ "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/icu-messageformat-parser": {
+ "version": "2.7.6",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz",
+ "integrity": "sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "@formatjs/icu-skeleton-parser": "1.8.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/icu-skeleton-parser": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.0.tgz",
+ "integrity": "sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@formatjs/intl-localematcher": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
+ "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.13",
"dev": true,
@@ -3278,6 +3321,10 @@
"resolved": "packages/extension",
"link": true
},
+ "node_modules/@ps-analysis-tool/i18n": {
+ "resolved": "packages/i18n",
+ "link": true
+ },
"node_modules/@ps-analysis-tool/library-detection": {
"resolved": "packages/library-detection",
"link": true
@@ -6879,9 +6926,8 @@
},
"node_modules/@types/xml2js": {
"version": "0.4.14",
- "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz",
- "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/node": "*"
}
@@ -8429,9 +8475,8 @@
},
"node_modules/body-parser": {
"version": "1.20.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
- "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"content-type": "~1.0.5",
@@ -8453,24 +8498,21 @@
},
"node_modules/body-parser/node_modules/debug": {
"version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/body-parser/node_modules/qs": {
"version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
+ "license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.0.4"
},
@@ -8631,9 +8673,8 @@
},
"node_modules/bytes": {
"version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -9469,9 +9510,8 @@
},
"node_modules/content-type": {
"version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -9483,9 +9523,8 @@
},
"node_modules/cookie": {
"version": "0.6.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
- "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -10979,9 +11018,8 @@
},
"node_modules/es5-ext": {
"version": "0.10.64",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
- "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"hasInstallScript": true,
+ "license": "ISC",
"dependencies": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
@@ -11705,8 +11743,7 @@
},
"node_modules/esniff": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
- "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
+ "license": "ISC",
"dependencies": {
"d": "^1.0.1",
"es5-ext": "^0.10.62",
@@ -11719,8 +11756,7 @@
},
"node_modules/esniff/node_modules/type": {
"version": "2.7.2",
- "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
- "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
+ "license": "ISC"
},
"node_modules/espree": {
"version": "9.6.1",
@@ -11902,9 +11938,8 @@
},
"node_modules/express": {
"version": "4.19.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
- "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
@@ -12385,8 +12420,6 @@
},
"node_modules/follow-redirects": {
"version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"dev": true,
"funding": [
{
@@ -12394,6 +12427,7 @@
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
+ "license": "MIT",
"engines": {
"node": ">=4.0"
},
@@ -13245,6 +13279,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/html-inline-script-webpack-plugin": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/html-inline-script-webpack-plugin/-/html-inline-script-webpack-plugin-3.2.1.tgz",
+ "integrity": "sha512-PEj9Ve31BE0dva6eTD6wHMOztgIdPxF6gx3wad7ohBkCn7MXpuUvPC9t5ThMJ2NrVi1jWGBYU76DfoS+8dabRw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.0.0",
+ "npm": ">=6.0.0"
+ },
+ "peerDependencies": {
+ "html-webpack-plugin": "^5.0.0",
+ "webpack": "^5.0.0"
+ }
+ },
"node_modules/html-minifier-terser": {
"version": "6.1.0",
"dev": true,
@@ -13453,9 +13501,8 @@
},
"node_modules/iconv-lite": {
"version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
@@ -13672,6 +13719,17 @@
"node": ">=10.13.0"
}
},
+ "node_modules/intl-messageformat": {
+ "version": "10.5.11",
+ "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.11.tgz",
+ "integrity": "sha512-eYq5fkFBVxc7GIFDzpFQkDOZgNayNTQn4Oufe8jw6YY6OHVw70/4pA3FyCsQ0Gb2DnvEJEMmN2tOaXUGByM+kg==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "@formatjs/fast-memoize": "2.2.0",
+ "@formatjs/icu-messageformat-parser": "2.7.6",
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/invariant": {
"version": "2.2.4",
"dev": true,
@@ -13682,8 +13740,7 @@
},
"node_modules/ip": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
- "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ=="
+ "license": "MIT"
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
@@ -17161,9 +17218,8 @@
},
"node_modules/media-typer": {
"version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -18260,8 +18316,7 @@
},
"node_modules/pac-resolver": {
"version": "7.0.1",
- "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
- "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+ "license": "MIT",
"dependencies": {
"degenerator": "^5.0.0",
"netmask": "^2.0.2"
@@ -19237,9 +19292,8 @@
},
"node_modules/raw-body": {
"version": "2.5.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
- "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
@@ -19260,8 +19314,7 @@
},
"node_modules/react": {
"version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "license": "MIT",
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -21428,9 +21481,10 @@
}
},
"node_modules/tar": {
- "version": "6.2.0",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"dev": true,
- "license": "ISC",
"dependencies": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
@@ -22125,9 +22179,8 @@
},
"node_modules/type-is": {
"version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
@@ -22476,8 +22529,7 @@
},
"node_modules/use-context-selector": {
"version": "1.4.1",
- "resolved": "https://registry.npmjs.org/use-context-selector/-/use-context-selector-1.4.1.tgz",
- "integrity": "sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA==",
+ "license": "MIT",
"peerDependencies": {
"react": ">=16.8.0",
"react-dom": "*",
@@ -23432,9 +23484,8 @@
},
"node_modules/webpack-dev-middleware": {
"version": "6.1.2",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz",
- "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"colorette": "^2.0.10",
"memfs": "^3.4.12",
@@ -23657,9 +23708,8 @@
},
"node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": {
"version": "5.3.4",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
- "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"colorette": "^2.0.10",
"memfs": "^3.4.3",
@@ -24244,7 +24294,7 @@
},
"packages/cli": {
"name": "@ps-analysis-tool/cli",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"dependencies": {
"@ps-analysis-tool/common": "*",
@@ -24274,7 +24324,7 @@
},
"packages/cli-dashboard": {
"name": "@ps-analysis-tool/cli-dashboard",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"dependencies": {
"@ps-analysis-tool/common": "*",
@@ -25001,8 +25051,7 @@
},
"packages/cli/node_modules/xml2js": {
"version": "0.6.2",
- "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
- "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
+ "license": "MIT",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
@@ -25013,24 +25062,24 @@
},
"packages/common": {
"name": "@ps-analysis-tool/common",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"dependencies": {
"tldts": "^6.0.14"
},
"devDependencies": {
- "devtools-protocol": "^0.0.1236148"
+ "devtools-protocol": "^0.0.1282316"
}
},
"packages/common/node_modules/devtools-protocol": {
- "version": "0.0.1236148",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1236148.tgz",
- "integrity": "sha512-fCOlpTqzzeCpbHaYUJAraMIP1a8D4FNzHDnUaIfZCeK9XMUONKjfLISkLXX56wDgQ93omAiTAFoSR3maAGz5Dg==",
+ "version": "0.0.1282316",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1282316.tgz",
+ "integrity": "sha512-i7eIqWdVxeXBY/M+v83yRkOV1sTHnr3XYiC0YNBivLIE6hBfE2H0c2o8VC5ynT44yjy+Ei0kLrBQFK/RUKaAHQ==",
"dev": true
},
"packages/design-system": {
"name": "@ps-analysis-tool/design-system",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"dependencies": {
"@ps-analysis-tool/common": "*",
@@ -25041,7 +25090,7 @@
},
"packages/eslint-import-resolver": {
"name": "@ps-analysis-tool/eslint-import-resolver",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"dependencies": {
"eslint-import-resolver-node": "^0.3.7"
@@ -25049,7 +25098,7 @@
},
"packages/extension": {
"name": "@ps-analysis-tool/extension",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"dependencies": {
"@floating-ui/core": "^1.5.0",
@@ -25076,18 +25125,27 @@
},
"devDependencies": {
"@types/react-copy-to-clipboard": "^5.0.4",
- "devtools-protocol": "^0.0.1236148"
+ "devtools-protocol": "^0.0.1282316",
+ "html-inline-script-webpack-plugin": "^3.2.1"
}
},
"packages/extension/node_modules/devtools-protocol": {
- "version": "0.0.1236148",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1236148.tgz",
- "integrity": "sha512-fCOlpTqzzeCpbHaYUJAraMIP1a8D4FNzHDnUaIfZCeK9XMUONKjfLISkLXX56wDgQ93omAiTAFoSR3maAGz5Dg==",
+ "version": "0.0.1282316",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1282316.tgz",
+ "integrity": "sha512-i7eIqWdVxeXBY/M+v83yRkOV1sTHnr3XYiC0YNBivLIE6hBfE2H0c2o8VC5ynT44yjy+Ei0kLrBQFK/RUKaAHQ==",
"dev": true
},
+ "packages/i18n": {
+ "name": "@ps-analysis-tool/i18n",
+ "version": "0.7.0",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "intl-messageformat": "^10.5.11"
+ }
+ },
"packages/library-detection": {
"name": "@ps-analysis-tool/library-detection",
- "version": "0.6.0",
+ "version": "0.7.0",
"license": "Apache-2.0",
"dependencies": {
"@ps-analysis-tool/common": "*",
@@ -25100,13 +25158,11 @@
},
"packages/library-detection/node_modules/classnames": {
"version": "2.5.1",
- "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
- "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
+ "license": "MIT"
},
"packages/library-detection/node_modules/escape-string-regexp": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -25122,8 +25178,6 @@
},
"@adobe/css-tools": {
"version": "4.3.2",
- "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz",
- "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==",
"dev": true
},
"@alloc/quick-lru": {
@@ -26433,6 +26487,50 @@
"@floating-ui/utils": {
"version": "0.1.6"
},
+ "@formatjs/ecma402-abstract": {
+ "version": "1.18.2",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz",
+ "integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==",
+ "requires": {
+ "@formatjs/intl-localematcher": "0.5.4",
+ "tslib": "^2.4.0"
+ }
+ },
+ "@formatjs/fast-memoize": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.0.tgz",
+ "integrity": "sha512-hnk/nY8FyrL5YxwP9e4r9dqeM6cAbo8PeU9UjyXojZMNvVad2Z06FAVHyR3Ecw6fza+0GH7vdJgiKIVXTMbSBA==",
+ "requires": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "@formatjs/icu-messageformat-parser": {
+ "version": "2.7.6",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.7.6.tgz",
+ "integrity": "sha512-etVau26po9+eewJKYoiBKP6743I1br0/Ie00Pb/S/PtmYfmjTcOn2YCh2yNkSZI12h6Rg+BOgQYborXk46BvkA==",
+ "requires": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "@formatjs/icu-skeleton-parser": "1.8.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "@formatjs/icu-skeleton-parser": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.0.tgz",
+ "integrity": "sha512-QWLAYvM0n8hv7Nq5BEs4LKIjevpVpbGLAJgOaYzg9wABEoX1j0JO1q2/jVkO6CVlq0dbsxZCngS5aXbysYueqA==",
+ "requires": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "tslib": "^2.4.0"
+ }
+ },
+ "@formatjs/intl-localematcher": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
+ "integrity": "sha512-zTwEpWOzZ2CiKcB93BLngUX59hQkuZjT2+SAQEscSm52peDW/getsawMcWF1rGRpMCX6D7nSJA3CzJ8gn13N/g==",
+ "requires": {
+ "tslib": "^2.4.0"
+ }
+ },
"@humanwhocodes/config-array": {
"version": "0.11.13",
"dev": true,
@@ -27133,8 +27231,6 @@
},
"xml2js": {
"version": "0.6.2",
- "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
- "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
@@ -27524,14 +27620,14 @@
"@ps-analysis-tool/common": {
"version": "file:packages/common",
"requires": {
- "devtools-protocol": "^0.0.1236148",
+ "devtools-protocol": "^0.0.1282316",
"tldts": "^6.0.14"
},
"dependencies": {
"devtools-protocol": {
- "version": "0.0.1236148",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1236148.tgz",
- "integrity": "sha512-fCOlpTqzzeCpbHaYUJAraMIP1a8D4FNzHDnUaIfZCeK9XMUONKjfLISkLXX56wDgQ93omAiTAFoSR3maAGz5Dg==",
+ "version": "0.0.1282316",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1282316.tgz",
+ "integrity": "sha512-i7eIqWdVxeXBY/M+v83yRkOV1sTHnr3XYiC0YNBivLIE6hBfE2H0c2o8VC5ynT44yjy+Ei0kLrBQFK/RUKaAHQ==",
"dev": true
}
}
@@ -27560,9 +27656,10 @@
"@ps-analysis-tool/library-detection": "*",
"@types/react-copy-to-clipboard": "^5.0.4",
"classnames": "^2.3.2",
- "devtools-protocol": "^0.0.1236148",
+ "devtools-protocol": "^0.0.1282316",
"fast-xml-parser": "^4.3.2",
"file-saver": "^2.0.5",
+ "html-inline-script-webpack-plugin": "^3.2.1",
"p-queue": "^7.3.4",
"re-resizable": "^6.9.9",
"react": "^18.2.0",
@@ -27579,13 +27676,19 @@
},
"dependencies": {
"devtools-protocol": {
- "version": "0.0.1236148",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1236148.tgz",
- "integrity": "sha512-fCOlpTqzzeCpbHaYUJAraMIP1a8D4FNzHDnUaIfZCeK9XMUONKjfLISkLXX56wDgQ93omAiTAFoSR3maAGz5Dg==",
+ "version": "0.0.1282316",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1282316.tgz",
+ "integrity": "sha512-i7eIqWdVxeXBY/M+v83yRkOV1sTHnr3XYiC0YNBivLIE6hBfE2H0c2o8VC5ynT44yjy+Ei0kLrBQFK/RUKaAHQ==",
"dev": true
}
}
},
+ "@ps-analysis-tool/i18n": {
+ "version": "file:packages/i18n",
+ "requires": {
+ "intl-messageformat": "^10.5.11"
+ }
+ },
"@ps-analysis-tool/library-detection": {
"version": "file:packages/library-detection",
"requires": {
@@ -27598,14 +27701,10 @@
},
"dependencies": {
"classnames": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
- "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
+ "version": "2.5.1"
},
"escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
+ "version": "4.0.0"
}
}
},
@@ -29862,8 +29961,6 @@
},
"@types/xml2js": {
"version": "0.4.14",
- "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz",
- "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -30838,8 +30935,6 @@
},
"body-parser": {
"version": "1.20.2",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
- "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
"dev": true,
"requires": {
"bytes": "3.1.2",
@@ -30858,8 +30953,6 @@
"dependencies": {
"debug": {
"version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -30867,14 +30960,10 @@
},
"ms": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"dev": true
},
"qs": {
"version": "6.11.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
- "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dev": true,
"requires": {
"side-channel": "^1.0.4"
@@ -30972,8 +31061,6 @@
},
"bytes": {
"version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"dev": true
},
"c8": {
@@ -31503,8 +31590,6 @@
},
"content-type": {
"version": "1.0.5",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
- "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"dev": true
},
"convert-source-map": {
@@ -31513,8 +31598,6 @@
},
"cookie": {
"version": "0.6.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
- "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
"dev": true
},
"cookie-signature": {
@@ -32478,8 +32561,6 @@
},
"es5-ext": {
"version": "0.10.64",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz",
- "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
"requires": {
"es6-iterator": "^2.0.3",
"es6-symbol": "^3.1.3",
@@ -32951,8 +33032,6 @@
},
"esniff": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz",
- "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
"requires": {
"d": "^1.0.1",
"es5-ext": "^0.10.62",
@@ -32961,9 +33040,7 @@
},
"dependencies": {
"type": {
- "version": "2.7.2",
- "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
- "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
+ "version": "2.7.2"
}
}
},
@@ -33083,8 +33160,6 @@
},
"express": {
"version": "4.19.2",
- "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
- "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
"dev": true,
"requires": {
"accepts": "~1.3.8",
@@ -33435,8 +33510,6 @@
},
"follow-redirects": {
"version": "1.15.6",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
- "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"dev": true
},
"for-each": {
@@ -33963,6 +34036,13 @@
"version": "2.0.2",
"dev": true
},
+ "html-inline-script-webpack-plugin": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/html-inline-script-webpack-plugin/-/html-inline-script-webpack-plugin-3.2.1.tgz",
+ "integrity": "sha512-PEj9Ve31BE0dva6eTD6wHMOztgIdPxF6gx3wad7ohBkCn7MXpuUvPC9t5ThMJ2NrVi1jWGBYU76DfoS+8dabRw==",
+ "dev": true,
+ "requires": {}
+ },
"html-minifier-terser": {
"version": "6.1.0",
"dev": true,
@@ -34088,8 +34168,6 @@
},
"iconv-lite": {
"version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dev": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
@@ -34209,6 +34287,17 @@
"version": "3.1.1",
"dev": true
},
+ "intl-messageformat": {
+ "version": "10.5.11",
+ "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.5.11.tgz",
+ "integrity": "sha512-eYq5fkFBVxc7GIFDzpFQkDOZgNayNTQn4Oufe8jw6YY6OHVw70/4pA3FyCsQ0Gb2DnvEJEMmN2tOaXUGByM+kg==",
+ "requires": {
+ "@formatjs/ecma402-abstract": "1.18.2",
+ "@formatjs/fast-memoize": "2.2.0",
+ "@formatjs/icu-messageformat-parser": "2.7.6",
+ "tslib": "^2.4.0"
+ }
+ },
"invariant": {
"version": "2.2.4",
"dev": true,
@@ -34217,9 +34306,7 @@
}
},
"ip": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz",
- "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ=="
+ "version": "2.0.1"
},
"ipaddr.js": {
"version": "1.9.1",
@@ -36367,8 +36454,6 @@
},
"media-typer": {
"version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"dev": true
},
"memfs": {
@@ -37066,8 +37151,6 @@
},
"pac-resolver": {
"version": "7.0.1",
- "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
- "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
"requires": {
"degenerator": "^5.0.0",
"netmask": "^2.0.2"
@@ -37640,8 +37723,6 @@
},
"raw-body": {
"version": "2.5.2",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
- "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"dev": true,
"requires": {
"bytes": "3.1.2",
@@ -37656,8 +37737,6 @@
},
"react": {
"version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
"requires": {
"loose-envify": "^1.1.0"
}
@@ -39058,7 +39137,9 @@
"dev": true
},
"tar": {
- "version": "6.2.0",
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
"dev": true,
"requires": {
"chownr": "^2.0.0",
@@ -39517,8 +39598,6 @@
},
"type-is": {
"version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dev": true,
"requires": {
"media-typer": "0.3.0",
@@ -39729,8 +39808,6 @@
},
"use-context-selector": {
"version": "1.4.1",
- "resolved": "https://registry.npmjs.org/use-context-selector/-/use-context-selector-1.4.1.tgz",
- "integrity": "sha512-Io2ArvcRO+6MWIhkdfMFt+WKQX+Vb++W8DS2l03z/Vw/rz3BclKpM0ynr4LYGyU85Eke+Yx5oIhTY++QR0ZDoA==",
"requires": {}
},
"use-debounce": {
@@ -40349,8 +40426,6 @@
},
"webpack-dev-middleware": {
"version": "6.1.2",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz",
- "integrity": "sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==",
"dev": true,
"requires": {
"colorette": "^2.0.10",
@@ -40485,8 +40560,6 @@
},
"webpack-dev-middleware": {
"version": "5.3.4",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
- "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
"dev": true,
"requires": {
"colorette": "^2.0.10",
diff --git a/package.json b/package.json
index a1719976f..d02400cde 100644
--- a/package.json
+++ b/package.json
@@ -1,19 +1,18 @@
{
"name": "ps-analysis-tool",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "Cookie Analysis Tool and CLI for analysis and understanding of cookie usage on web pages.",
"scripts": {
"cli:prebuild": "node ./scripts/delete-build-artifacts.cjs",
"cli:dev": "tsc-watch --build",
"cli:build": "npm run cli:prebuild && tsc --build",
- "cli-dashboard:start": "npm run dev --workspace=@ps-analysis-tool/cli-dashboard",
"cli-dashboard:dev": "npm run dev --workspace=@ps-analysis-tool/cli-dashboard",
"cli-dashboard:build": "npm run build --workspace=@ps-analysis-tool/cli-dashboard",
"cli": "node dist/cli/index.js",
"test": "jest --config=tests/jest.config.cjs",
"test:coverage": "npm run test -- --collectCoverage && open coverage/lcov-report/index.html",
"dev": "npm run dev --workspace=@ps-analysis-tool/extension",
- "build": "npm run build --workspace=@ps-analysis-tool/extension",
+ "build": "rm -rf dist/extension && npm run build --workspace=@ps-analysis-tool/extension",
"serve": "webpack serve",
"lint": "npm-run-all --parallel lint:*",
"lint:js": "eslint .",
@@ -22,6 +21,7 @@
"prepare": "husky install",
"cookie-db:update": "node scripts/update-cookie-db.cjs",
"rws-json:update": "node scripts/update-rws-json.cjs",
+ "merge-i18n-messages": "node packages/i18n/scripts/merge-messages.cjs",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"start": "npm install && npm run dev"
diff --git a/packages/cli-dashboard/package.json b/packages/cli-dashboard/package.json
index 28a415dfc..147798102 100644
--- a/packages/cli-dashboard/package.json
+++ b/packages/cli-dashboard/package.json
@@ -1,6 +1,6 @@
{
"name": "@ps-analysis-tool/cli-dashboard",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "Dashboard for visualizing cli analysis output",
"repository": {
"type": "git",
diff --git a/packages/cli-dashboard/src/app.css b/packages/cli-dashboard/src/app.css
index e03eb3376..28f8b7bc9 100644
--- a/packages/cli-dashboard/src/app.css
+++ b/packages/cli-dashboard/src/app.css
@@ -7,3 +7,12 @@
display: none;
}
}
+@layer base {
+ body {
+ @apply font-sans;
+ }
+ :root {
+ --color-message-box-dark: 33deg 14% 18%;
+ --color-message-box-light: 30deg 100% 75%;
+ }
+}
diff --git a/packages/cli-dashboard/src/components/affectedCookies/index.tsx b/packages/cli-dashboard/src/components/cookiesWithIssues/index.tsx
similarity index 79%
rename from packages/cli-dashboard/src/components/affectedCookies/index.tsx
rename to packages/cli-dashboard/src/components/cookiesWithIssues/index.tsx
index 39ae7768b..d987c7768 100644
--- a/packages/cli-dashboard/src/components/affectedCookies/index.tsx
+++ b/packages/cli-dashboard/src/components/cookiesWithIssues/index.tsx
@@ -25,20 +25,28 @@ import { type CookieTableData } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import useCookieListing from '../../hooks/useCookieListing.tsx';
+import useCookieListing from '../../hooks/useCookieListing';
-interface AffectedCookiesProps {
+interface CookiesWithIssuesProps {
cookies: CookieTableData[];
selectedSite: string | null;
}
-const AffectedCookies = ({ cookies, selectedSite }: AffectedCookiesProps) => {
+const CookiesWithIssues = ({
+ cookies,
+ selectedSite,
+}: CookiesWithIssuesProps) => {
const [selectedFrameCookie, setSelectedFrameCookie] = useState<{
[frame: string]: CookieTableData | null;
} | null>(null);
const { tableColumns, filters, searchKeys, tablePersistentSettingsKey } =
- useCookieListing(cookies, 'frame', 'affectedCookiesListing', selectedSite);
+ useCookieListing(
+ cookies,
+ 'frame',
+ 'cookiesWithIssuesListing',
+ selectedSite
+ );
return (
@@ -58,10 +66,8 @@ const AffectedCookies = ({ cookies, selectedSite }: AffectedCookiesProps) => {
className="h-full flex"
>
({ ...cookie, isBlocked: undefined }))} // Hot Fix: To unhighlight cookies in the Affected Cookie table.
- useIsBlockedToHighlight={true} // Hot Fix: To use isBlocked to highlight cookies in the Affected Cookie table.
+ data={cookies.map((cookie) => ({ ...cookie, isBlocked: undefined }))} // Hot Fix: To unhighlight cookies in the Cookies with issues table.
tableColumns={tableColumns}
- showTopBar={true}
tableFilters={filters}
tableSearchKeys={searchKeys}
tablePersistentSettingsKey={tablePersistentSettingsKey}
@@ -73,10 +79,10 @@ const AffectedCookies = ({ cookies, selectedSite }: AffectedCookiesProps) => {
);
};
-export default AffectedCookies;
+export default CookiesWithIssues;
diff --git a/packages/cli-dashboard/src/components/siteMapReport/index.tsx b/packages/cli-dashboard/src/components/siteMapReport/index.tsx
index c9521a1ff..fc0c3777b 100644
--- a/packages/cli-dashboard/src/components/siteMapReport/index.tsx
+++ b/packages/cli-dashboard/src/components/siteMapReport/index.tsx
@@ -17,19 +17,13 @@
/**
* External dependencies.
*/
-import React, { useEffect, useMemo, useState } from 'react';
-import { Resizable } from 're-resizable';
+import React, { useState } from 'react';
import {
- File,
- FileWhite,
- Sidebar,
- useSidebar,
+ SidebarProvider,
type SidebarItems,
} from '@ps-analysis-tool/design-system';
import {
- type TabFrames,
type TechnologyData,
- UNKNOWN_FRAME_KEY,
type CookieFrameStorageType,
type CompleteJson,
} from '@ps-analysis-tool/common';
@@ -37,12 +31,8 @@ import {
/**
* Internal dependencies.
*/
-import SiteReport from '../siteReport';
-import SiteMapAffectedCookies from './sitemapAffectedCookies';
-import CookiesLandingContainer from '../siteReport/tabs/cookies/cookiesLandingContainer';
-import reshapeCookies from '../utils/reshapeCookies';
import sidebarData from './sidebarData';
-import { generateSiteMapReportandDownload } from '../utils/reportDownloader';
+import Layout from './layout';
interface SiteMapReportProps {
landingPageCookies: CookieFrameStorageType;
@@ -57,168 +47,19 @@ const SiteMapReport = ({
landingPageCookies,
completeJson,
}: SiteMapReportProps) => {
- const [sites, setSites] = useState([]);
const [data, setData] = useState(sidebarData);
- useEffect(() => {
- const _sites = new Set();
- Object.values(cookies).forEach((cookieData) => {
- Object.values(cookieData).forEach((cookie) => {
- _sites.add(cookie.pageUrl || '');
- });
- });
-
- setSites(Array.from(_sites));
- }, [cookies]);
-
- const frames = useMemo(() => {
- return Object.keys(cookies).reduce((acc, frame) => {
- if (frame?.includes('http') || frame === UNKNOWN_FRAME_KEY) {
- acc[frame] = {} as TabFrames[string];
- }
- return acc;
- }, {} as TabFrames);
- }, [cookies]);
-
- const reshapedCookies = useMemo(
- () => reshapeCookies(landingPageCookies),
- [landingPageCookies]
- );
-
- const affectedCookies = useMemo(
- () =>
- Object.fromEntries(
- Object.entries(reshapedCookies).filter(([, cookie]) => cookie.isBlocked)
- ),
- [reshapedCookies]
- );
-
- const {
- activePanel,
- selectedItemKey,
- sidebarItems,
- isSidebarFocused,
- setIsSidebarFocused,
- updateSelectedItemKey,
- onKeyNavigation,
- toggleDropdown,
- isKeyAncestor,
- isKeySelected,
- } = useSidebar({ data });
-
- const siteFilteredCookies = useMemo(() => {
- return Object.entries(cookies).reduce(
- (acc: CookieFrameStorageType, [frame, _cookies]) => {
- acc[frame] = Object.fromEntries(
- Object.entries(_cookies).filter(([, cookie]) =>
- isKeySelected(cookie.pageUrl || '')
- )
- );
-
- return acc;
- },
- {}
- );
- }, [cookies, isKeySelected]);
-
- const siteFilteredTechnologies = useMemo(() => {
- return technologies.filter((technology) =>
- isKeySelected(technology.pageUrl || '')
- );
- }, [isKeySelected, technologies]);
-
- useEffect(() => {
- setData((prev) => {
- const _data = { ...prev };
-
- _data['sitemap-landing-page'].panel = (
- {
- if (!Array.isArray(completeJson)) {
- return;
- }
-
- generateSiteMapReportandDownload(completeJson);
- }}
- />
- );
-
- _data['sitemap-landing-page'].children = sites.reduce(
- (acc: SidebarItems, site: string) => {
- acc[site] = {
- title: site,
- panel: (
-
- ),
- children: {},
- icon: ,
- selectedIcon: ,
- };
-
- return acc;
- },
- {}
- );
-
- _data['sitemap-affected-cookies'].panel = (
- cookie.isBlocked
- )}
- />
- );
-
- return _data;
- });
- }, [
- affectedCookies,
- completeJson,
- frames,
- isKeySelected,
- reshapedCookies,
- siteFilteredCookies,
- siteFilteredTechnologies,
- sites,
- ]);
-
- useEffect(() => {
- if (selectedItemKey === null && Object.keys(data).length > 0) {
- updateSelectedItemKey('sitemap-landing-page');
- }
- }, [data, isKeySelected, selectedItemKey, updateSelectedItemKey]);
-
return (
-
+
+
+
);
};
diff --git a/packages/cli-dashboard/src/components/siteMapReport/layout.tsx b/packages/cli-dashboard/src/components/siteMapReport/layout.tsx
new file mode 100644
index 000000000..ef381cc60
--- /dev/null
+++ b/packages/cli-dashboard/src/components/siteMapReport/layout.tsx
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import React, { useEffect, useMemo, useState } from 'react';
+import { Resizable } from 're-resizable';
+import {
+ File,
+ FileWhite,
+ Sidebar,
+ useSidebar,
+ type SidebarItems,
+ SIDEBAR_ITEMS_KEYS,
+} from '@ps-analysis-tool/design-system';
+import {
+ type TabFrames,
+ type TechnologyData,
+ type CookieFrameStorageType,
+ type CompleteJson,
+} from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import SiteReport from '../siteReport';
+import SiteMapCookiesWithIssues from './sitemapCookiesWithIssues';
+import CookiesLandingContainer from '../siteReport/tabs/cookies/cookiesLandingContainer';
+import reshapeCookies from '../utils/reshapeCookies';
+import { generateSiteMapReportandDownload } from '../utils/reportDownloader';
+
+interface LayoutProps {
+ landingPageCookies: CookieFrameStorageType;
+ cookies: CookieFrameStorageType;
+ technologies: TechnologyData[];
+ completeJson: CompleteJson[] | null;
+ sidebarData: SidebarItems;
+ setSidebarData: React.Dispatch>;
+}
+
+const Layout = ({
+ cookies,
+ technologies,
+ landingPageCookies,
+ completeJson,
+ sidebarData,
+ setSidebarData,
+}: LayoutProps) => {
+ const [sites, setSites] = useState([]);
+
+ useEffect(() => {
+ const _sites = new Set();
+ Object.values(cookies).forEach((cookieData) => {
+ Object.values(cookieData).forEach((cookie) => {
+ _sites.add(cookie.pageUrl || '');
+ });
+ });
+
+ setSites(Array.from(_sites));
+ }, [cookies]);
+
+ const reshapedCookies = useMemo(
+ () => reshapeCookies(landingPageCookies),
+ [landingPageCookies]
+ );
+
+ const cookiesWithIssues = useMemo(
+ () =>
+ Object.fromEntries(
+ Object.entries(reshapedCookies).filter(([, cookie]) => cookie.isBlocked)
+ ),
+ [reshapedCookies]
+ );
+
+ const { activePanel, selectedItemKey, updateSelectedItemKey, isKeySelected } =
+ useSidebar(({ state, actions }) => ({
+ activePanel: state.activePanel,
+ selectedItemKey: state.selectedItemKey,
+ updateSelectedItemKey: actions.updateSelectedItemKey,
+ isKeySelected: actions.isKeySelected,
+ }));
+
+ const { Element: PanelElement, props } = activePanel.panel;
+
+ const siteFilteredCookies = useMemo(() => {
+ return Object.entries(cookies).reduce(
+ (acc: CookieFrameStorageType, [frame, _cookies]) => {
+ acc[frame] = Object.fromEntries(
+ Object.entries(_cookies).filter(([, cookie]) =>
+ isKeySelected(cookie.pageUrl || '')
+ )
+ );
+
+ return acc;
+ },
+ {}
+ );
+ }, [cookies, isKeySelected]);
+
+ const siteFilteredTechnologies = useMemo(() => {
+ return technologies.filter((technology) =>
+ isKeySelected(technology.pageUrl || '')
+ );
+ }, [isKeySelected, technologies]);
+
+ useEffect(() => {
+ setSidebarData((prev) => {
+ const _data = { ...prev };
+
+ _data[SIDEBAR_ITEMS_KEYS.COOKIES].panel = {
+ Element: CookiesLandingContainer,
+ props: {
+ tabCookies: reshapedCookies,
+ tabFrames: sites.reduce((acc, site) => {
+ acc[site] = {} as TabFrames[string];
+
+ return acc;
+ }, {}),
+ cookiesWithIssues,
+ downloadReport: () => {
+ if (!Array.isArray(completeJson)) {
+ return;
+ }
+
+ generateSiteMapReportandDownload(completeJson);
+ },
+ },
+ };
+
+ _data[SIDEBAR_ITEMS_KEYS.COOKIES].children = sites.reduce(
+ (acc: SidebarItems, site: string) => {
+ acc[site] = {
+ title: site,
+ panel: {
+ Element: SiteReport,
+ props: {
+ cookies: siteFilteredCookies,
+ technologies: siteFilteredTechnologies,
+ completeJson,
+ selectedSite: site,
+ },
+ },
+ children: {},
+ icon: {
+ Element: File,
+ },
+ selectedIcon: {
+ Element: FileWhite,
+ },
+ };
+
+ return acc;
+ },
+ {}
+ );
+
+ _data[SIDEBAR_ITEMS_KEYS.COOKIES_WITH_ISSUES].panel = {
+ Element: SiteMapCookiesWithIssues,
+ props: {
+ cookies: Object.values(reshapedCookies).filter(
+ (cookie) => cookie.isBlocked
+ ),
+ },
+ };
+
+ return _data;
+ });
+ }, [
+ completeJson,
+ cookiesWithIssues,
+ isKeySelected,
+ reshapedCookies,
+ setSidebarData,
+ siteFilteredCookies,
+ siteFilteredTechnologies,
+ sites,
+ ]);
+
+ useEffect(() => {
+ if (selectedItemKey === null && Object.keys(sidebarData).length > 0) {
+ updateSelectedItemKey(SIDEBAR_ITEMS_KEYS.COOKIES);
+ }
+ }, [isKeySelected, selectedItemKey, sidebarData, updateSelectedItemKey]);
+
+ return (
+
+ );
+};
+
+export default Layout;
diff --git a/packages/cli-dashboard/src/components/siteMapReport/sidebarData.tsx b/packages/cli-dashboard/src/components/siteMapReport/sidebarData.ts
similarity index 68%
rename from packages/cli-dashboard/src/components/siteMapReport/sidebarData.tsx
rename to packages/cli-dashboard/src/components/siteMapReport/sidebarData.ts
index a1b143d90..6f3b8a2e8 100644
--- a/packages/cli-dashboard/src/components/siteMapReport/sidebarData.tsx
+++ b/packages/cli-dashboard/src/components/siteMapReport/sidebarData.ts
@@ -16,23 +16,33 @@
/**
* External dependencies
*/
-import React from 'react';
import {
- CookieIcon,
- CookieIconWhite,
+ SIDEBAR_ITEMS_KEYS,
+ WarningBare,
type SidebarItems,
} from '@ps-analysis-tool/design-system';
const sidebarData: SidebarItems = {
- 'sitemap-landing-page': {
+ [SIDEBAR_ITEMS_KEYS.COOKIES]: {
title: 'Sitemap Report',
children: {},
+ dropdownOpen: true,
},
- 'sitemap-affected-cookies': {
- title: 'Affected Cookies',
+ [SIDEBAR_ITEMS_KEYS.COOKIES_WITH_ISSUES]: {
+ title: 'Cookie Issues',
children: {},
- icon: ,
- selectedIcon: ,
+ icon: {
+ Element: WarningBare,
+ props: {
+ className: 'fill-granite-gray',
+ },
+ },
+ selectedIcon: {
+ Element: WarningBare,
+ props: {
+ className: 'fill-white',
+ },
+ },
},
};
diff --git a/packages/cli-dashboard/src/components/siteMapReport/sitemapAffectedCookies.tsx b/packages/cli-dashboard/src/components/siteMapReport/sitemapCookiesWithIssues.tsx
similarity index 73%
rename from packages/cli-dashboard/src/components/siteMapReport/sitemapAffectedCookies.tsx
rename to packages/cli-dashboard/src/components/siteMapReport/sitemapCookiesWithIssues.tsx
index 646116f50..ffa2c023c 100644
--- a/packages/cli-dashboard/src/components/siteMapReport/sitemapAffectedCookies.tsx
+++ b/packages/cli-dashboard/src/components/siteMapReport/sitemapCookiesWithIssues.tsx
@@ -23,14 +23,16 @@ import type { CookieTableData } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import AffectedCookies from '../affectedCookies';
+import CookiesWithIssues from '../cookiesWithIssues';
-interface SiteMapAffectedCookiesProps {
+interface SiteMapCookiesWithIssuesProps {
cookies: CookieTableData[];
}
-const SiteMapAffectedCookies = ({ cookies }: SiteMapAffectedCookiesProps) => {
- return ;
+const SiteMapCookiesWithIssues = ({
+ cookies,
+}: SiteMapCookiesWithIssuesProps) => {
+ return ;
};
-export default SiteMapAffectedCookies;
+export default SiteMapCookiesWithIssues;
diff --git a/packages/cli-dashboard/src/components/siteReport/components/layout.tsx b/packages/cli-dashboard/src/components/siteReport/components/layout.tsx
index ed5d019eb..992d67328 100644
--- a/packages/cli-dashboard/src/components/siteReport/components/layout.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/components/layout.tsx
@@ -16,7 +16,7 @@
/**
* External dependencies.
*/
-import React, { useEffect, useMemo, useRef, useState } from 'react';
+import React, { useEffect, useMemo, useRef } from 'react';
import { Resizable } from 're-resizable';
import {
CookieIcon,
@@ -26,24 +26,24 @@ import {
type SidebarItems,
SiteBoundariesIcon,
SiteBoundariesIconWhite,
+ SIDEBAR_ITEMS_KEYS,
} from '@ps-analysis-tool/design-system';
+import { UNKNOWN_FRAME_KEY } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
import { useContentStore } from '../stateProviders/contentStore';
-import { UNKNOWN_FRAME_KEY } from '@ps-analysis-tool/common';
-import TABS from '../tabs';
import CookiesTab from '../tabs/cookies';
-import SiteAffectedCookies from '../tabs/siteAffectedCookies';
+import SiteCookiesWithIssues from '../tabs/siteCookiesWithIssues';
import Technologies from '../tabs/technologies';
interface LayoutProps {
selectedSite: string | null;
+ setSidebarData: React.Dispatch>;
}
-const Layout = ({ selectedSite }: LayoutProps) => {
- const [data, setData] = useState(TABS);
+const Layout = ({ selectedSite, setSidebarData }: LayoutProps) => {
const { tabCookies, technologies } = useContentStore(({ state }) => ({
tabCookies: state.tabCookies,
technologies: state.technologies,
@@ -65,46 +65,52 @@ const Layout = ({ selectedSite }: LayoutProps) => {
[tabCookies]
);
- const {
- activePanel,
- selectedItemKey,
- sidebarItems,
- isSidebarFocused,
- setIsSidebarFocused,
- updateSelectedItemKey,
- onKeyNavigation,
- toggleDropdown,
- isKeyAncestor,
- isKeySelected,
- } = useSidebar({ data });
+ const { activePanel, selectedItemKey, updateSelectedItemKey } = useSidebar(
+ ({ state, actions }) => ({
+ activePanel: state.activePanel,
+ selectedItemKey: state.selectedItemKey,
+ updateSelectedItemKey: actions.updateSelectedItemKey,
+ })
+ );
+
+ const { Element: PanelElement, props } = activePanel.panel;
useEffect(() => {
- setData((prev) => {
+ setSidebarData((prev) => {
const _data = { ...prev };
const keys = selectedItemKey?.split('#') ?? [];
- _data['cookies'].panel = (
-
- );
+ _data[SIDEBAR_ITEMS_KEYS.COOKIES].panel = {
+ Element: CookiesTab,
+ props: {
+ selectedFrameUrl: null,
+ selectedSite,
+ },
+ };
const selectedFrameUrl = frameUrls.find(
(url) => url === keys[keys.length - 1]
);
- _data['cookies'].children = frameUrls.reduce(
+ _data[SIDEBAR_ITEMS_KEYS.COOKIES].children = frameUrls.reduce(
(acc: SidebarItems, url: string): SidebarItems => {
acc[url] = {
title: url,
- panel: (
-
- ),
+ panel: {
+ Element: CookiesTab,
+ props: {
+ selectedFrameUrl,
+ selectedSite,
+ },
+ },
children: {},
- icon: ,
- selectedIcon: ,
+ icon: {
+ Element: CookieIcon,
+ },
+ selectedIcon: {
+ Element: CookieIconWhite,
+ },
};
return acc;
@@ -112,29 +118,41 @@ const Layout = ({ selectedSite }: LayoutProps) => {
{}
);
- _data['affected-cookies'].panel = (
-
- );
+ _data[SIDEBAR_ITEMS_KEYS.COOKIES_WITH_ISSUES].panel = {
+ Element: SiteCookiesWithIssues,
+ props: {
+ selectedSite,
+ },
+ };
if (technologies && technologies.length > 0) {
- _data['technologies'] = {
+ _data[SIDEBAR_ITEMS_KEYS.TECHNOLOGIES] = {
title: 'Technologies',
children: {},
- icon: ,
- selectedIcon: ,
- panel: ,
+ icon: {
+ Element: SiteBoundariesIcon,
+ },
+ selectedIcon: {
+ Element: SiteBoundariesIconWhite,
+ },
+ panel: {
+ Element: Technologies,
+ props: {
+ selectedSite,
+ },
+ },
};
} else {
- delete _data['technologies'];
+ delete _data[SIDEBAR_ITEMS_KEYS.TECHNOLOGIES];
}
return _data;
});
- }, [frameUrls, selectedItemKey, selectedSite, technologies]);
+ }, [frameUrls, selectedItemKey, selectedSite, setSidebarData, technologies]);
useEffect(() => {
if (selectedItemKey === null) {
- updateSelectedItemKey('cookies');
+ updateSelectedItemKey(SIDEBAR_ITEMS_KEYS.COOKIES);
}
}, [selectedItemKey, updateSelectedItemKey]);
@@ -142,7 +160,7 @@ const Layout = ({ selectedSite }: LayoutProps) => {
useEffect(() => {
if (selectedSite !== lastSelectedSite.current) {
- updateSelectedItemKey('cookies');
+ updateSelectedItemKey(SIDEBAR_ITEMS_KEYS.COOKIES);
lastSelectedSite.current = selectedSite;
}
}, [selectedSite, updateSelectedItemKey]);
@@ -157,19 +175,14 @@ const Layout = ({ selectedSite }: LayoutProps) => {
right: true,
}}
>
-
+
- {activePanel}
+
);
};
diff --git a/packages/cli-dashboard/src/components/siteReport/index.tsx b/packages/cli-dashboard/src/components/siteReport/index.tsx
index bcb710bd3..6299268bf 100644
--- a/packages/cli-dashboard/src/components/siteReport/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/index.tsx
@@ -17,18 +17,23 @@
/**
* External dependencies
*/
-import React from 'react';
+import React, { useState } from 'react';
import type {
CompleteJson,
CookieJsonDataType,
TechnologyData,
} from '@ps-analysis-tool/common';
+import {
+ SidebarProvider,
+ type SidebarItems,
+} from '@ps-analysis-tool/design-system';
/**
* Internal dependencies.
*/
import { Provider as ContentStoreProvider } from './stateProviders/contentStore';
import Layout from './components/layout';
+import Tabs from './tabs';
interface SiteReportProps {
cookies: {
@@ -47,13 +52,17 @@ const SiteReport = ({
completeJson,
selectedSite,
}: SiteReportProps) => {
+ const [data, setData] = useState(Tabs);
+
return (
-
+
+
+
);
};
diff --git a/packages/cli-dashboard/src/components/siteReport/stateProviders/contentStore/index.tsx b/packages/cli-dashboard/src/components/siteReport/stateProviders/contentStore/index.tsx
index 638344766..71544cbd8 100644
--- a/packages/cli-dashboard/src/components/siteReport/stateProviders/contentStore/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/stateProviders/contentStore/index.tsx
@@ -17,12 +17,13 @@
* External dependencies.
*/
import React, { type PropsWithChildren, useMemo } from 'react';
-import { useContextSelector, createContext } from 'use-context-selector';
import {
type CompleteJson,
type CookieJsonDataType,
type CookieTableData,
type TechnologyData,
+ useContextSelector,
+ createContext,
} from '@ps-analysis-tool/common';
/**
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/blockedCookiesSection.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/blockedCookiesSection.tsx
new file mode 100644
index 000000000..a9c6c7d8e
--- /dev/null
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/blockedCookiesSection.tsx
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ CookiesLandingWrapper,
+ type DataMapping,
+ prepareCookieStatsComponents,
+ prepareCookiesCount,
+ MatrixContainer,
+ type MatrixComponentProps,
+ LEGEND_DESCRIPTION,
+ useFiltersMapping,
+} from '@ps-analysis-tool/design-system';
+import type { TabCookies, TabFrames } from '@ps-analysis-tool/common';
+
+interface BlockedCookiesSectionProps {
+ tabCookies: TabCookies | null;
+ cookiesWithIssues: TabCookies | null;
+ tabFrames: TabFrames | null;
+}
+
+const BlockedCookiesSection = ({
+ tabCookies,
+ cookiesWithIssues,
+ tabFrames,
+}: BlockedCookiesSectionProps) => {
+ const { selectedItemUpdater } = useFiltersMapping(tabFrames || {});
+ const cookieStats = prepareCookiesCount(tabCookies);
+ const cookiesStatsComponents = prepareCookieStatsComponents(cookieStats);
+ const blockedCookieDataMapping: DataMapping[] = [
+ {
+ title: 'Blocked cookies',
+ count: cookieStats.blockedCookies.total,
+ data: cookiesStatsComponents.blocked,
+ onClick: () => selectedItemUpdater('All', 'blockedReasons'),
+ },
+ ];
+ const dataComponents: MatrixComponentProps[] =
+ cookiesStatsComponents.blockedCookiesLegend.map((component) => {
+ const legendDescription = LEGEND_DESCRIPTION[component.label] || '';
+ return {
+ ...component,
+ description: legendDescription,
+ title: component.label,
+ containerClasses: '',
+ onClick: (title: string) =>
+ selectedItemUpdater(title, 'blockedReasons'),
+ };
+ });
+
+ const blockedCookiesStats = prepareCookiesCount(cookiesWithIssues);
+ const blockedCookiesStatsComponents =
+ prepareCookieStatsComponents(blockedCookiesStats);
+ const blockedDataComponents: MatrixComponentProps[] =
+ blockedCookiesStatsComponents.legend.map((component) => {
+ const legendDescription = LEGEND_DESCRIPTION[component.label] || '';
+ return {
+ ...component,
+ description: legendDescription,
+ title: component.label,
+ containerClasses: '',
+ };
+ });
+
+ return (
+
+ {dataComponents.length > 0 && (
+ <>
+
+
+ >
+ )}
+
+ );
+};
+export default BlockedCookiesSection;
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/cookiesSection.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/cookiesSection.tsx
new file mode 100644
index 000000000..a595afa7c
--- /dev/null
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/cookiesSection.tsx
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React, { useMemo } from 'react';
+import {
+ CookiesLandingWrapper,
+ CookiesMatrix,
+ MessageBox,
+ prepareCookieDataMapping,
+ prepareCookieStatsComponents,
+ prepareCookiesCount,
+ useFiltersMapping,
+} from '@ps-analysis-tool/design-system';
+import type { TabCookies, TabFrames } from '@ps-analysis-tool/common';
+/**
+ * Internal dependencies
+ */
+
+interface CookiesSectionProps {
+ tabCookies: TabCookies | null;
+ tabFrames: TabFrames | null;
+}
+const CookiesSection = ({ tabCookies, tabFrames }: CookiesSectionProps) => {
+ const { selectedItemUpdater } = useFiltersMapping(tabFrames || {});
+
+ const cookieStats = prepareCookiesCount(tabCookies);
+ const cookiesStatsComponents = prepareCookieStatsComponents(cookieStats);
+ const cookieClassificationDataMapping = prepareCookieDataMapping(
+ cookieStats,
+ cookiesStatsComponents,
+ selectedItemUpdater
+ );
+
+ const cookieComponentData = useMemo(() => {
+ return cookiesStatsComponents.legend.map((component) => ({
+ ...component,
+ onClick: (title: string) =>
+ selectedItemUpdater(title, 'analytics.category'),
+ }));
+ }, [cookiesStatsComponents.legend, selectedItemUpdater]);
+
+ return (
+
+ {!cookieStats ||
+ (cookieStats?.firstParty.total === 0 &&
+ cookieStats?.thirdParty.total === 0 && (
+
+ ))}
+
+
+ );
+};
+export default CookiesSection;
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/index.ts b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/index.ts
new file mode 100644
index 000000000..50e480013
--- /dev/null
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/cookieLanding/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as CookiesSection } from './cookiesSection';
+export { default as BlockedCookiesSection } from './blockedCookiesSection';
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/index.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/index.tsx
index 8d45e44d9..1fb51a9f7 100644
--- a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesLandingContainer/index.tsx
@@ -17,67 +17,78 @@
/**
* External dependencies.
*/
-import React from 'react';
+import React, { useMemo } from 'react';
import {
- Button,
CookiesLanding,
- CookiesMatrix,
- prepareCookiesCount,
- prepareCookieStatsComponents,
+ MenuBar,
+ type CookiesLandingSection,
+ type MenuData,
} from '@ps-analysis-tool/design-system';
import type { TabCookies, TabFrames } from '@ps-analysis-tool/common';
+import CookiesSection from './cookieLanding/cookiesSection';
+import BlockedCookiesSection from './cookieLanding/blockedCookiesSection';
interface CookiesLandingContainerProps {
tabFrames: TabFrames;
tabCookies: TabCookies;
- affectedCookies: TabCookies;
+ cookiesWithIssues: TabCookies;
downloadReport?: () => void;
}
const CookiesLandingContainer = ({
tabFrames,
tabCookies,
- affectedCookies,
+ cookiesWithIssues,
downloadReport,
}: CookiesLandingContainerProps) => {
+ const sections: Array = useMemo(
+ () => [
+ {
+ name: 'Cookies',
+ link: 'cookies',
+ panel: {
+ Element: CookiesSection,
+ props: {
+ tabCookies,
+ tabFrames,
+ },
+ },
+ },
+ {
+ name: 'Blocked Cookies',
+ link: 'blocked-cookies',
+ panel: {
+ Element: BlockedCookiesSection,
+ props: {
+ tabCookies,
+ cookiesWithIssues,
+ tabFrames,
+ },
+ },
+ },
+ ],
+ [tabCookies, tabFrames, cookiesWithIssues]
+ );
+
+ const menuData: MenuData = useMemo(
+ () => sections.map(({ name, link }) => ({ name, link })),
+ [sections]
+ );
+
return (
<>
- {downloadReport && (
-
-
-
- )}
-
-
-
-
+
+
+ {sections.map(({ link, panel: { Element, props } }) => (
+
+ {Element && }
-
+ ))}
>
);
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesListing/index.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesListing/index.tsx
index ce9893bcb..4e4bf7006 100644
--- a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesListing/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/cookiesListing/index.tsx
@@ -25,7 +25,7 @@ import type { CookieTableData } from '@ps-analysis-tool/common';
/**
* Internal dependencies
*/
-import useCookieListing from '../../../../../hooks/useCookieListing.tsx';
+import useCookieListing from '../../../../../hooks/useCookieListing';
import { useContentStore } from '../../../stateProviders/contentStore';
/**
@@ -57,13 +57,18 @@ const CookiesListing = ({
[tabCookies, selectedFrameUrl]
);
- const { tableColumns, filters, searchKeys, tablePersistentSettingsKey } =
- useCookieListing(
- Object.values(tabCookies),
- selectedFrameUrl,
- 'cookiesListing',
- selectedSite
- );
+ const {
+ tableColumns,
+ filters,
+ searchKeys,
+ tablePersistentSettingsKey,
+ isSidebarOpen,
+ } = useCookieListing(
+ Object.values(tabCookies),
+ selectedFrameUrl,
+ 'cookiesListing',
+ selectedSite
+ );
return (
@@ -80,21 +85,19 @@ const CookiesListing = ({
className="h-full flex"
>
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/index.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/index.tsx
index 94aec4e6f..33c43ac2b 100644
--- a/packages/cli-dashboard/src/components/siteReport/tabs/cookies/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/cookies/index.tsx
@@ -48,7 +48,7 @@ const CookiesTab = ({ selectedFrameUrl, selectedSite }: CookiesTabProps) => {
[tabCookies]
);
- const affectedCookies = useMemo(
+ const cookiesWithIssues = useMemo(
() =>
Object.fromEntries(
Object.entries(tabCookies).filter(([, cookie]) => cookie.isBlocked)
@@ -78,7 +78,7 @@ const CookiesTab = ({ selectedFrameUrl, selectedSite }: CookiesTabProps) => {
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/index.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/index.ts
similarity index 64%
rename from packages/cli-dashboard/src/components/siteReport/tabs/index.tsx
rename to packages/cli-dashboard/src/components/siteReport/tabs/index.ts
index d71a4c481..4e98a7a7b 100644
--- a/packages/cli-dashboard/src/components/siteReport/tabs/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/index.ts
@@ -16,25 +16,40 @@
/**
* External dependencies.
*/
-import React from 'react';
import {
CookieIcon,
CookieIconWhite,
+ SIDEBAR_ITEMS_KEYS,
+ WarningBare,
type SidebarItems,
} from '@ps-analysis-tool/design-system';
const Tabs: SidebarItems = {
- cookies: {
+ [SIDEBAR_ITEMS_KEYS.COOKIES]: {
title: 'Cookies',
children: {},
- icon: ,
- selectedIcon: ,
+ icon: {
+ Element: CookieIcon,
+ },
+ selectedIcon: {
+ Element: CookieIconWhite,
+ },
},
- 'affected-cookies': {
- title: 'Affected Cookies',
+ [SIDEBAR_ITEMS_KEYS.COOKIES_WITH_ISSUES]: {
+ title: 'Cookie Issues',
children: {},
- icon: ,
- selectedIcon: ,
+ icon: {
+ Element: WarningBare,
+ props: {
+ className: 'fill-granite-gray',
+ },
+ },
+ selectedIcon: {
+ Element: WarningBare,
+ props: {
+ className: 'fill-white',
+ },
+ },
},
};
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/siteAffectedCookies/index.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/siteCookiesWithIssues/index.tsx
similarity index 76%
rename from packages/cli-dashboard/src/components/siteReport/tabs/siteAffectedCookies/index.tsx
rename to packages/cli-dashboard/src/components/siteReport/tabs/siteCookiesWithIssues/index.tsx
index 4c8ab29e6..29de488a4 100644
--- a/packages/cli-dashboard/src/components/siteReport/tabs/siteAffectedCookies/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/siteCookiesWithIssues/index.tsx
@@ -22,21 +22,23 @@ import React from 'react';
/**
* Internal dependencies
*/
-import AffectedCookies from '../../../affectedCookies';
+import CookiesWithIssues from '../../../cookiesWithIssues';
import { useContentStore } from '../../stateProviders/contentStore';
-interface SiteAffectedCookiesProps {
+interface SiteCookiesWithIssuesProps {
selectedSite: string | null;
}
-const SiteAffectedCookies = ({ selectedSite }: SiteAffectedCookiesProps) => {
+const SiteCookiesWithIssues = ({
+ selectedSite,
+}: SiteCookiesWithIssuesProps) => {
const { tabCookies } = useContentStore(({ state }) => ({
tabCookies: Object.values(state.tabCookies).filter(
(cookie) => cookie.isBlocked
),
}));
- return ;
+ return ;
};
-export default SiteAffectedCookies;
+export default SiteCookiesWithIssues;
diff --git a/packages/cli-dashboard/src/components/siteReport/tabs/technologies/index.tsx b/packages/cli-dashboard/src/components/siteReport/tabs/technologies/index.tsx
index e87d05008..416e0d67d 100644
--- a/packages/cli-dashboard/src/components/siteReport/tabs/technologies/index.tsx
+++ b/packages/cli-dashboard/src/components/siteReport/tabs/technologies/index.tsx
@@ -21,13 +21,13 @@ import React, { useMemo, useState } from 'react';
import { Resizable } from 're-resizable';
import {
Table,
- useTable,
type TableColumn,
type InfoType,
type TableRow,
type TableFilter,
+ TableProvider,
} from '@ps-analysis-tool/design-system';
-import type { TechnologyData } from '@ps-analysis-tool/common';
+import { noop, type TechnologyData } from '@ps-analysis-tool/common';
/**
* Internal dependencies
@@ -94,14 +94,6 @@ const Technologies = ({ selectedSite }: TechnologiesProps) => {
return 'technologyListing';
}, [selectedSite]);
- const table = useTable({
- data,
- tableColumns,
- tableFilterData: filters,
- tableSearchKeys: searchKeys,
- tablePersistentSettingsKey,
- });
-
return (
{
}}
className="h-full flex"
>
- {
setSelectedRow(row as TechnologyData);
}}
+ onRowContextMenu={noop}
getRowObjectKey={(row: TableRow) => {
return (row.originalData as TechnologyData).slug;
}}
- />
+ >
+
+
{selectedRow ? (
diff --git a/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteMapReportandDownload.ts b/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteMapReportandDownload.ts
index 6b599d45f..2349b811b 100644
--- a/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteMapReportandDownload.ts
+++ b/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteMapReportandDownload.ts
@@ -31,10 +31,18 @@ const generateSiteMapReportandDownload = async (JSONReport: CompleteJson[]) => {
return;
}
+ const today = new Date();
+
+ const day = String(today.getDate()).padStart(2, '0'); // Get the day and ensure it has leading zero if needed
+ const month = String(today.getMonth() + 1).padStart(2, '0'); // Get the month and ensure it has leading zero if needed
+ const year = today.getFullYear();
+
const zip = new JSZip();
JSONReport.forEach((data) => {
- const zipFolder: JSZip | null = zip.folder(getFolderName(data.pageUrl));
+ const zipFolder: JSZip | null = zip.folder(
+ `psat_cli_report_${getFolderName(data.pageUrl)}_${day + month + year}`
+ );
if (!zipFolder) {
return;
@@ -44,7 +52,12 @@ const generateSiteMapReportandDownload = async (JSONReport: CompleteJson[]) => {
});
const content = await zip.generateAsync({ type: 'blob' });
- saveAs(content, 'report.zip');
+ saveAs(
+ content,
+ `psat_cli_report_${getFolderName(JSONReport[0].pageUrl)}_${
+ day + month + year
+ }.zip`
+ );
};
export default generateSiteMapReportandDownload;
diff --git a/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteReportandDownload.ts b/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteReportandDownload.ts
index 8ea038705..5416e6215 100644
--- a/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteReportandDownload.ts
+++ b/packages/cli-dashboard/src/components/utils/reportDownloader/generateSiteReportandDownload.ts
@@ -33,6 +33,12 @@ const generateSiteReportandDownload = async (
return;
}
+ const today = new Date();
+
+ const day = String(today.getDate()).padStart(2, '0'); // Get the day and ensure it has leading zero if needed
+ const month = String(today.getMonth() + 1).padStart(2, '0'); // Get the month and ensure it has leading zero if needed
+ const year = today.getFullYear();
+
const zip = new JSZip();
let siteAnalysisData: CompleteJson;
@@ -46,7 +52,9 @@ const generateSiteReportandDownload = async (
}
const zipFolder: JSZip | null = zip.folder(
- getFolderName(siteAnalysisData.pageUrl)
+ `psat_cli_report_${getFolderName(JSONReport[0].pageUrl)}_${
+ day + month + year
+ }`
);
if (!zipFolder) {
@@ -56,7 +64,12 @@ const generateSiteReportandDownload = async (
createZip(siteAnalysisData, zipFolder);
const content = await zip.generateAsync({ type: 'blob' });
- saveAs(content, 'report.zip');
+ saveAs(
+ content,
+ `psat_cli_report_${getFolderName(JSONReport[0].pageUrl)}_${
+ day + month + year
+ }.zip`
+ );
};
export default generateSiteReportandDownload;
diff --git a/packages/cli-dashboard/src/components/utils/reportDownloader/utils.ts b/packages/cli-dashboard/src/components/utils/reportDownloader/utils.ts
index eb033c3ae..fa94bf39e 100644
--- a/packages/cli-dashboard/src/components/utils/reportDownloader/utils.ts
+++ b/packages/cli-dashboard/src/components/utils/reportDownloader/utils.ts
@@ -19,7 +19,7 @@
*/
import type JSZip from 'jszip';
import {
- generateAffectedCookiesCSV,
+ generateCookiesWithIssuesCSV,
generateAllCookiesCSV,
generateSummaryDataCSV,
generateTechnologyCSV,
@@ -32,13 +32,13 @@ const generateCSVFiles = (data: CompleteJson) => {
if (data.technologyData.length > 0) {
technologyDataCSV = generateTechnologyCSV(data);
}
- const affectedCookiesDataCSV = generateAffectedCookiesCSV(data);
+ const cookiesWithIssuesDataCSV = generateCookiesWithIssuesCSV(data);
const summaryDataCSV = generateSummaryDataCSV(data);
return {
allCookiesCSV,
technologyDataCSV,
- affectedCookiesDataCSV,
+ cookiesWithIssuesDataCSV,
summaryDataCSV,
};
};
@@ -47,7 +47,7 @@ export const createZip = (analysisData: CompleteJson, zipObject: JSZip) => {
const {
allCookiesCSV,
technologyDataCSV,
- affectedCookiesDataCSV,
+ cookiesWithIssuesDataCSV,
summaryDataCSV,
} = generateCSVFiles(analysisData);
@@ -55,7 +55,7 @@ export const createZip = (analysisData: CompleteJson, zipObject: JSZip) => {
if (technologyDataCSV) {
zipObject.file('technologies.csv', technologyDataCSV);
}
- zipObject.file('affected-cookies.csv', affectedCookiesDataCSV);
+ zipObject.file('cookie-issues.csv', cookiesWithIssuesDataCSV);
zipObject.file('report.csv', summaryDataCSV);
zipObject.file('report.json', JSON.stringify(analysisData, null, 4));
};
@@ -64,7 +64,8 @@ export const getFolderName = (pageUrl: string) => {
let folderName = pageUrl
.trim()
.replace(/^https?:\/\//, '')
- .replace(/\/+/g, '-');
+ .replace(/\/+/g, '-')
+ .replace(/\./g, '-');
if (folderName.endsWith('-')) {
const lastDashIndex = folderName.lastIndexOf('-');
diff --git a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/calculateBlockedReasonsFilterValues.tsx b/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/calculateBlockedReasonsFilterValues.tsx
deleted file mode 100644
index 6af116efb..000000000
--- a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/calculateBlockedReasonsFilterValues.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * External dependencies
- */
-import { getValueByKey, type CookieTableData } from '@ps-analysis-tool/common';
-import type { TableFilter } from '@ps-analysis-tool/design-system';
-
-const calculateBlockedReasonsFilterValues = (tabCookies: CookieTableData[]) => {
- return tabCookies.reduce
(
- (acc, cookie) => {
- const blockedReason = getValueByKey('blockedReasons', cookie);
-
- if (!cookie.frameIdList || cookie?.frameIdList?.length === 0) {
- return acc;
- }
-
- blockedReason?.forEach((reason: string) => {
- if (!acc) {
- acc = {};
- }
-
- acc[reason] = {
- selected: false,
- };
- });
-
- return acc;
- },
- {}
- );
-};
-
-export default calculateBlockedReasonsFilterValues;
diff --git a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/calculateDynamicFilterValues.ts b/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/calculateDynamicFilterValues.ts
deleted file mode 100644
index abc6cfda1..000000000
--- a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/calculateDynamicFilterValues.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * External dependencies
- */
-import { getValueByKey, type CookieTableData } from '@ps-analysis-tool/common';
-import type { TableFilter } from '@ps-analysis-tool/design-system';
-
-const calculateDynamicFilterValues = (
- key: string,
- tabCookies: CookieTableData[]
-): TableFilter[keyof TableFilter]['filterValues'] => {
- return tabCookies.reduce(
- (acc, cookie) => {
- const value = getValueByKey(key, cookie);
-
- if (!acc) {
- acc = {};
- }
-
- if (value) {
- acc[value] = {
- selected: false,
- };
- }
-
- return acc;
- },
- {}
- );
-};
-
-export default calculateDynamicFilterValues;
diff --git a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/index.tsx b/packages/cli-dashboard/src/hooks/useCookieListing/index.tsx
similarity index 84%
rename from packages/cli-dashboard/src/hooks/useCookieListing.tsx/index.tsx
rename to packages/cli-dashboard/src/hooks/useCookieListing/index.tsx
index d9117dbbd..928b81314 100644
--- a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/index.tsx
+++ b/packages/cli-dashboard/src/hooks/useCookieListing/index.tsx
@@ -18,28 +18,39 @@
* External dependencies
*/
import React, { useMemo } from 'react';
-import type {
- InfoType,
- TableColumn,
- TableFilter,
+import {
+ useSidebar,
+ type InfoType,
+ type TableColumn,
+ type TableFilter,
+ calculateBlockedReasonsFilterValues,
+ calculateDynamicFilterValues,
+ evaluateSelectAllOption,
+ evaluateStaticFilterValues,
} from '@ps-analysis-tool/design-system';
import {
calculateEffectiveExpiryDate,
type CookieTableData,
} from '@ps-analysis-tool/common';
-/**
- * Internal dependencies
- */
-import calculateDynamicFilterValues from './utils/calculateDynamicFilterValues';
-import calculateBlockedReasonsFilterValues from './utils/calculateBlockedReasonsFilterValues';
-
const useCookieListing = (
tabCookies: CookieTableData[],
selectedFrameUrl: string,
persistenceKey = 'cookiesListing',
selectedSite?: string | null
) => {
+ const { activePanelQuery, clearActivePanelQuery } = useSidebar(
+ ({ state }) => ({
+ activePanelQuery: state.activePanel.query,
+ clearActivePanelQuery: state.activePanel.clearQuery,
+ })
+ );
+
+ const parsedQuery = useMemo(
+ () => JSON.parse(activePanelQuery || '{}'),
+ [activePanelQuery]
+ );
+
const tableColumns = useMemo(
() => [
{
@@ -140,7 +151,9 @@ const useCookieListing = (
hasPrecalculatedFilterValues: true,
filterValues: calculateDynamicFilterValues(
'analytics.category',
- tabCookies
+ tabCookies,
+ parsedQuery?.filter?.['analytics.category'],
+ clearActivePanelQuery
),
sortValues: true,
useGenericPersistenceKey: true,
@@ -148,14 +161,20 @@ const useCookieListing = (
isFirstParty: {
title: 'Scope',
hasStaticFilterValues: true,
- filterValues: {
- 'First Party': {
- selected: false,
- },
- 'Third Party': {
- selected: false,
+ hasPrecalculatedFilterValues: true,
+ filterValues: evaluateStaticFilterValues(
+ {
+ 'First Party': {
+ selected: false,
+ },
+ 'Third Party': {
+ selected: false,
+ },
},
- },
+ 'isFirstParty',
+ parsedQuery,
+ clearActivePanelQuery
+ ),
useGenericPersistenceKey: true,
comparator: (value: InfoType, filterValue: string) => {
const val = Boolean(value);
@@ -277,7 +296,9 @@ const useCookieListing = (
hasPrecalculatedFilterValues: true,
filterValues: calculateDynamicFilterValues(
'analytics.platform',
- tabCookies
+ tabCookies,
+ parsedQuery?.filter?.['analytics.platform'],
+ clearActivePanelQuery
),
sortValues: true,
useGenericPersistenceKey: true,
@@ -287,7 +308,16 @@ const useCookieListing = (
hasStaticFilterValues: true,
hasPrecalculatedFilterValues: true,
enableSelectAllOption: true,
- filterValues: calculateBlockedReasonsFilterValues(tabCookies),
+ isSelectAllOptionSelected: evaluateSelectAllOption(
+ 'blockedReasons',
+ parsedQuery,
+ clearActivePanelQuery
+ ),
+ filterValues: calculateBlockedReasonsFilterValues(
+ tabCookies,
+ parsedQuery?.filter?.blockedReasons,
+ clearActivePanelQuery
+ ),
sortValues: true,
useGenericPersistenceKey: true,
comparator: (value: InfoType, filterValue: string) => {
@@ -295,7 +325,7 @@ const useCookieListing = (
},
},
}),
- [tabCookies]
+ [clearActivePanelQuery, parsedQuery, tabCookies]
);
const searchKeys = useMemo(
@@ -316,6 +346,7 @@ const useCookieListing = (
filters,
searchKeys,
tablePersistentSettingsKey,
+ isSidebarOpen: parsedQuery?.filter ? true : false,
};
};
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 6f13fd66e..c6c0f90c1 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@ps-analysis-tool/cli",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "CLI tool for analysis",
"main": "index.js",
"scripts": {
diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts
index e45f06ece..90ccd32e3 100644
--- a/packages/cli/src/index.ts
+++ b/packages/cli/src/index.ts
@@ -46,7 +46,7 @@ const DELAY_TIME = 20000;
const program = new Command();
program
- .version('0.6.0')
+ .version('0.7.0')
.description('CLI to test a URL for 3p cookies')
.option('-u, --url ', 'URL of a site')
.option('-s, --sitemap-url ', 'URL of a sitemap')
@@ -55,6 +55,7 @@ program
'-p, --sitemap-path ',
'Path to a sitemap saved in the file system'
)
+ .option('-po, --port ', 'A port for the CLI dashboard server.')
.option('-ul, --url-limit ', 'No of URLs to analyze')
.option(
'-nh, --no-headless ',
@@ -68,23 +69,14 @@ program
.option(
'-d, --out-dir ',
'Directory path where the analysis data will be stored'
+ )
+ .option(
+ '-ab, --accept-banner',
+ 'This will accept the GDPR banner if present.'
);
program.parse();
-const initialize = async () => {
- //check if devserver port in already in use
-
- const portInUse = await checkPortInUse(9000);
-
- if (portInUse) {
- console.error(
- 'Error: Report server port (9000) already in use. You might be already running CLI'
- );
- process.exit(1);
- }
-};
-
const saveResults = async (
outDir: string,
result: CompleteJson | CompleteJson[]
@@ -93,29 +85,27 @@ const saveResults = async (
await writeFile(outDir + '/out.json', JSON.stringify(result, null, 4));
};
-const startDashboardServer = async (dir: string) => {
- exec('npm run cli-dashboard:dev');
+const startDashboardServer = async (dir: string, port: number) => {
+ exec(`npm run cli-dashboard:dev -- -- --port ${port}`);
await delay(2000);
- console.log(
- `Report is being served at the URL: http://localhost:9000?dir=${dir}`
- );
+ console.log(`Report: http://localhost:${port}?dir=${dir}`);
};
// eslint-disable-next-line complexity
(async () => {
- await initialize();
-
const url = program.opts().url;
const sitemapUrl = program.opts().sitemapUrl;
const csvPath = program.opts().csvPath;
const sitemapPath = program.opts().sitemapPath;
+ const port = parseInt(program.opts().port || '9000');
const numberOfUrlsInput = program.opts().urlLimit;
const isHeadless = Boolean(program.opts().headless);
const shouldSkipPrompts = !program.opts().prompts;
const shouldSkipTechnologyAnalysis = !program.opts().technology;
const outDir = program.opts().outDir;
+ const shouldSkipAcceptBanner = program.opts().acceptBanner;
validateArgs(
url,
@@ -123,9 +113,23 @@ const startDashboardServer = async (dir: string) => {
csvPath,
sitemapPath,
numberOfUrlsInput,
- outDir
+ outDir,
+ port
);
+ //check if devserver port in already in use only if the dashboard is goint to be used
+
+ if (!outDir) {
+ const isPortInUse = await checkPortInUse(port);
+
+ if (isPortInUse) {
+ console.error(
+ `Error: Report server port ${port} already in use. You might be already running CLI`
+ );
+ process.exit(1);
+ }
+ }
+
const prefix =
url || sitemapUrl
? Utility.generatePrefix(url || sitemapUrl)
@@ -178,7 +182,7 @@ const startDashboardServer = async (dir: string) => {
const cookieDictionary = await fetchDictionary();
spinnies.add('cookie-spinner', {
- text: 'Analysing cookies on first page visit',
+ text: 'Analysing cookies on first site visit',
});
const cookieAnalysisData = await analyzeCookiesUrlsInBatches(
@@ -187,7 +191,8 @@ const startDashboardServer = async (dir: string) => {
DELAY_TIME,
cookieDictionary,
3,
- urlsToProcess.length !== 1 ? spinnies : undefined
+ urlsToProcess.length !== 1 ? spinnies : undefined,
+ shouldSkipAcceptBanner
);
spinnies.succeed('cookie-spinner', {
@@ -229,6 +234,7 @@ const startDashboardServer = async (dir: string) => {
startDashboardServer(
encodeURIComponent(prefix) +
- (sitemapUrl || csvPath || sitemapPath ? '&type=sitemap' : '')
+ (sitemapUrl || csvPath || sitemapPath ? '&type=sitemap' : ''),
+ port
);
})();
diff --git a/packages/cli/src/procedures/analyzeCookieUrls.ts b/packages/cli/src/procedures/analyzeCookieUrls.ts
index 17a951309..93a8241f4 100644
--- a/packages/cli/src/procedures/analyzeCookieUrls.ts
+++ b/packages/cli/src/procedures/analyzeCookieUrls.ts
@@ -29,7 +29,8 @@ export const analyzeCookiesUrls = async (
urls: string[],
isHeadless: boolean,
delayTime: number,
- cookieDictionary: CookieDatabase
+ cookieDictionary: CookieDatabase,
+ shouldSkipAcceptBanner: boolean
) => {
const browser = new BrowserManagement(
{
@@ -43,7 +44,10 @@ export const analyzeCookiesUrls = async (
);
await browser.initializeBrowser(true);
- const analysisCookieData = await browser.analyzeCookieUrls(urls);
+ const analysisCookieData = await browser.analyzeCookieUrls(
+ urls,
+ shouldSkipAcceptBanner
+ );
const res = analysisCookieData.map(({ pageUrl, cookieData }) => {
Object.entries(cookieData).forEach(([, frameData]) => {
diff --git a/packages/cli/src/procedures/analyzeCookieUrlsInBatches.ts b/packages/cli/src/procedures/analyzeCookieUrlsInBatches.ts
index db27f6f2c..93df0200c 100644
--- a/packages/cli/src/procedures/analyzeCookieUrlsInBatches.ts
+++ b/packages/cli/src/procedures/analyzeCookieUrlsInBatches.ts
@@ -36,7 +36,8 @@ export const analyzeCookiesUrlsInBatches = async (
id: string,
{ text, indent }: { text: string; indent: number }
) => void;
- }
+ },
+ shouldSkipAcceptBanner = false
) => {
let report: {
pageUrl: string;
@@ -66,7 +67,8 @@ export const analyzeCookiesUrlsInBatches = async (
urlsWindow,
isHeadless,
delayTime,
- cookieDictionary
+ cookieDictionary,
+ shouldSkipAcceptBanner
);
report = [...report, ...cookieAnalysis];
diff --git a/packages/cli/src/utils/browserManagement/index.ts b/packages/cli/src/utils/browserManagement/index.ts
index 134b2a44f..c64b87468 100644
--- a/packages/cli/src/utils/browserManagement/index.ts
+++ b/packages/cli/src/utils/browserManagement/index.ts
@@ -75,6 +75,52 @@ export class BrowserManagement {
this.debugLog('browser intialized');
}
+ async clickOnAcceptBanner(url: string) {
+ const page = this.pageMap.get(url);
+
+ if (!page) {
+ throw new Error('no page with the provided id was found');
+ }
+
+ await page.evaluate(() => {
+ const bannerNodes: Element[] = Array.from(
+ (document.querySelector('body')?.childNodes || []) as Element[]
+ )
+ .filter((node: Element) => node && node?.tagName === 'DIV')
+ .filter((node) => {
+ if (!node || !node?.textContent) {
+ return false;
+ }
+ const regex =
+ /\b(consent|policy|cookie policy|privacy policy|personalize|preferences)\b/;
+
+ return regex.test(node.textContent.toLowerCase());
+ });
+
+ if (bannerNodes.length > 0) {
+ this.debugLog(`found GDPR banner in the page.`);
+ }
+
+ const buttonToClick: HTMLButtonElement[] = bannerNodes
+ .map((node: Element) => {
+ const buttonNodes = Array.from(node.getElementsByTagName('button'));
+ const isButtonForAccept = buttonNodes.filter(
+ (cnode) =>
+ cnode.textContent &&
+ (cnode.textContent.toLowerCase().includes('accept') ||
+ cnode.textContent.toLowerCase().includes('allow') ||
+ cnode.textContent.toLowerCase().includes('agree'))
+ );
+
+ return isButtonForAccept[0];
+ })
+ .filter((button) => button);
+ buttonToClick[0]?.click();
+ });
+
+ await delay(this.pageWaitTime / 2);
+ }
+
async openPage(): Promise {
if (!this.browser) {
throw new Error('Browser not intialized');
@@ -90,33 +136,51 @@ export class BrowserManagement {
height: 790,
deviceScaleFactor: 1,
});
+
this.debugLog('Page opened');
+
return sitePage;
}
- async navigateAndScroll(url: string) {
+ async navigateToPage(url: string) {
const page = this.pageMap.get(url);
+
if (!page) {
throw new Error('no page with the provided id was found');
}
+
this.debugLog(`starting navigation to url ${url}`);
+
try {
await page.goto(url, { timeout: 10000 });
+ this.debugLog(`done with navigation to url:${url}`);
} catch (error) {
this.debugLog(
`navigation did not finish in 10 seconds moving on to scrolling`
);
//ignore
}
+ }
- await delay(this.pageWaitTime / 2);
+ async pageScroll(url: string) {
+ const page = this.pageMap.get(url);
- await page.evaluate(() => {
- window.scrollBy(0, 10000);
- });
+ if (!page) {
+ throw new Error('no page with the provided id was found');
+ }
+
+ try {
+ await page.evaluate(() => {
+ window.scrollBy(0, 10000);
+ });
+ } catch (error) {
+ this.debugLog(`scrolling the page to the end.`);
+ //ignore
+ }
await delay(this.pageWaitTime / 2);
- this.debugLog(`done navigating and scrolling to url:${url}`);
+
+ this.debugLog(`scrolling on url:${url}`);
}
async attachNetworkListenersToPage(pageId: string) {
@@ -254,7 +318,7 @@ export class BrowserManagement {
return frameIdMapFromTree;
}
- async analyzeCookieUrls(urls: string[]) {
+ async analyzeCookieUrls(urls: string[], shouldSkipAcceptBanner: boolean) {
for (const url of urls) {
const sitePage = await this.openPage();
this.pageMap.set(url, sitePage);
@@ -264,7 +328,11 @@ export class BrowserManagement {
// start navigation in parallel
await Promise.all(
urls.map(async (url) => {
- await this.navigateAndScroll(url);
+ await this.navigateToPage(url);
+ if (shouldSkipAcceptBanner) {
+ await this.clickOnAcceptBanner(url);
+ }
+ await this.pageScroll(url);
})
);
@@ -297,7 +365,7 @@ export class BrowserManagement {
requestMap,
frameIdUrlMap,
mainFrameId,
- url
+ page.url()
);
const networkCookieKeySet = new Set();
diff --git a/packages/cli/src/utils/browserManagement/parseNetworkDataToCookieData.ts b/packages/cli/src/utils/browserManagement/parseNetworkDataToCookieData.ts
index a548826d4..a8f41e15b 100644
--- a/packages/cli/src/utils/browserManagement/parseNetworkDataToCookieData.ts
+++ b/packages/cli/src/utils/browserManagement/parseNetworkDataToCookieData.ts
@@ -85,11 +85,15 @@ export const parseNetworkDataToCookieData = (
data.responses?.forEach((response: ResponseData) => {
response.cookies.forEach((cookie) => {
// domain update required. Domain based on the server url
- const parsedDomain =
+ let parsedDomain =
cookie.parsedCookie.domain === ''
? getDomain(response.serverUrl)
: cookie.parsedCookie.domain;
+ if (parsedDomain && parsedDomain[0] !== '.') {
+ parsedDomain = '.' + parsedDomain;
+ }
+
const key =
cookie.parsedCookie.name +
':' +
@@ -119,11 +123,15 @@ export const parseNetworkDataToCookieData = (
data.requests?.forEach((request: RequestData) => {
request.cookies.forEach((cookie) => {
// domain update required. Domain based on the server url
- const parsedDomain =
+ let parsedDomain =
cookie.parsedCookie.domain === ''
? getDomain(request.serverUrl)
: cookie.parsedCookie.domain;
+ if (parsedDomain && parsedDomain[0] !== '.') {
+ parsedDomain = '.' + parsedDomain;
+ }
+
const key =
cookie.parsedCookie.name +
':' +
@@ -148,7 +156,7 @@ export const parseNetworkDataToCookieData = (
});
frameIdCookiesMap.set(frameId, {
- frameUrl: frameIdUrlMap.get(frameId) || pageUrl,
+ frameUrl: frameIdUrlMap.get(frameId) || new URL(pageUrl).origin,
frameCookies: Object.fromEntries(_frameCookies),
});
}
@@ -166,6 +174,7 @@ export const parseNetworkDataToCookieData = (
if (!data.frameUrl.includes('http')) {
continue;
}
+
const _url = new URL(data.frameUrl);
const newFrameCookies = {
diff --git a/packages/cli/src/utils/generateCSVfiles.ts b/packages/cli/src/utils/generateCSVfiles.ts
index c31746868..b29534698 100644
--- a/packages/cli/src/utils/generateCSVfiles.ts
+++ b/packages/cli/src/utils/generateCSVfiles.ts
@@ -18,7 +18,7 @@
*/
import {
CompleteJson,
- generateAffectedCookiesCSV,
+ generateCookiesWithIssuesCSV,
generateAllCookiesCSV,
generateSummaryDataCSV,
generateTechnologyCSV,
@@ -30,13 +30,13 @@ const generateCSVFiles = (data: CompleteJson) => {
if (data.technologyData.length > 0) {
technologyDataCSV = generateTechnologyCSV(data);
}
- const affectedCookiesDataCSV = generateAffectedCookiesCSV(data);
+ const cookiesWithIssuesDataCSV = generateCookiesWithIssuesCSV(data);
const summaryDataCSV = generateSummaryDataCSV(data);
return {
allCookiesCSV,
technologyDataCSV,
- affectedCookiesDataCSV,
+ cookiesWithIssuesDataCSV,
summaryDataCSV,
};
};
diff --git a/packages/cli/src/utils/saveCSVReports.ts b/packages/cli/src/utils/saveCSVReports.ts
index 479d53954..d8a1d5c55 100644
--- a/packages/cli/src/utils/saveCSVReports.ts
+++ b/packages/cli/src/utils/saveCSVReports.ts
@@ -47,7 +47,7 @@ const saveCSVReports = async (outDir: string, result: CompleteJson[]) => {
const {
allCookiesCSV,
technologyDataCSV,
- affectedCookiesDataCSV,
+ cookiesWithIssuesDataCSV,
summaryDataCSV,
} = generateCSVFiles(siteReport);
@@ -64,10 +64,10 @@ const saveCSVReports = async (outDir: string, result: CompleteJson[]) => {
);
}
- await ensureFile(path.join(fileDir, 'affected-cookies.csv'));
+ await ensureFile(path.join(fileDir, 'cookie-issues.csv'));
await writeFile(
- path.join(fileDir, 'affected-cookies.csv'),
- affectedCookiesDataCSV
+ path.join(fileDir, 'cookies-issues.csv'),
+ cookiesWithIssuesDataCSV
);
await ensureFile(path.join(fileDir, 'report.csv'));
@@ -79,7 +79,7 @@ const saveCSVReports = async (outDir: string, result: CompleteJson[]) => {
const {
allCookiesCSV,
technologyDataCSV,
- affectedCookiesDataCSV,
+ cookiesWithIssuesDataCSV,
summaryDataCSV,
} = generateCSVFiles(result[0]);
await ensureFile(path.join(outDir, 'cookies.csv'));
@@ -90,10 +90,10 @@ const saveCSVReports = async (outDir: string, result: CompleteJson[]) => {
await writeFile(path.join(outDir, 'technologies.csv'), technologyDataCSV);
}
- await ensureFile(path.join(outDir, 'affected-cookies.csv'));
+ await ensureFile(path.join(outDir, 'cookie-issues.csv'));
await writeFile(
- path.join(outDir, 'affected-cookies.csv'),
- affectedCookiesDataCSV
+ path.join(outDir, 'cookie-issues.csv'),
+ cookiesWithIssuesDataCSV
);
await ensureFile(path.join(outDir, 'report.csv'));
diff --git a/packages/cli/src/utils/tests/validateArgs.ts b/packages/cli/src/utils/tests/validateArgs.ts
index 2cf3df480..bcfb0c5f2 100644
--- a/packages/cli/src/utils/tests/validateArgs.ts
+++ b/packages/cli/src/utils/tests/validateArgs.ts
@@ -44,7 +44,7 @@ describe('validateArgs', () => {
return;
});
- validateArgs('https://example.com', '', '', '', '', '');
+ validateArgs('https://example.com', '', '', '', '', '', 9000);
expect(mockExit).toHaveBeenCalledTimes(0);
});
@@ -59,7 +59,7 @@ describe('validateArgs', () => {
jest.spyOn(fse, 'mkdir').mockImplementation(() => {
return;
});
- validateArgs('', '', '', '', '', '');
+ validateArgs('', '', '', '', '', '', 9000);
expect(mockExit).toHaveBeenCalled();
});
@@ -80,7 +80,8 @@ describe('validateArgs', () => {
'',
'',
'',
- ''
+ '',
+ 9000
);
expect(mockExit).toHaveBeenCalled();
@@ -92,7 +93,7 @@ describe('validateArgs', () => {
return false;
});
- validateArgs('', '', '', './path/list.xml', '', '');
+ validateArgs('', '', '', './path/list.xml', '', '', 9000);
expect(mockExit).toHaveBeenCalled();
});
@@ -103,7 +104,7 @@ describe('validateArgs', () => {
return true;
});
- validateArgs('', '', '', './path/list.xml', 'a', '');
+ validateArgs('', '', '', './path/list.xml', 'a', '', 9000);
expect(mockExit).toHaveBeenCalled();
});
diff --git a/packages/cli/src/utils/validateArgs.ts b/packages/cli/src/utils/validateArgs.ts
index 1b75e1c2e..f6753d7b2 100644
--- a/packages/cli/src/utils/validateArgs.ts
+++ b/packages/cli/src/utils/validateArgs.ts
@@ -26,6 +26,7 @@ import path from 'path';
* @param {string} sitemapPath File system path to a sitemap xml file.
* @param {string} numberOfUrls Url limit argument.
* @param {string} outDir File system path to the output directory.
+ * @param port
*/
// eslint-disable-next-line complexity
const validateArgs = async (
@@ -34,8 +35,14 @@ const validateArgs = async (
csvPath: string,
sitemapPath: string,
numberOfUrls: string,
- outDir: string
+ outDir: string,
+ port: number
) => {
+ if (isNaN(port) || (!isNaN(port) && (port < 0 || port > 65536))) {
+ console.log(`Invalid port argument. Please porvide a port >=0 and <=65536`);
+ process.exit(1);
+ }
+
const numArgs: number = [
Boolean(url),
Boolean(sitemapUrl),
@@ -94,9 +101,7 @@ const validateArgs = async (
if (outDir) {
const outDirExists = await exists(path.resolve(outDir));
if (!outDirExists) {
- console.log(
- `Provided dir "${path.resolve(outDir)}" does not exist. Creating now!!`
- );
+ console.log(`"${path.resolve(outDir)}" does not exist, creating now.`);
await mkdir(path.resolve(outDir));
}
}
diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json
index 9bd045188..9df306aff 100644
--- a/packages/cli/tsconfig.json
+++ b/packages/cli/tsconfig.json
@@ -9,5 +9,5 @@
"esModuleInterop": true,
"moduleResolution": "node"
},
- "references": [{ "path": "../common" }]
+ "references": [{ "path": "../common" }, { "path": "../i18n" }]
}
diff --git a/packages/common/package.json b/packages/common/package.json
index aad0a1bc0..f363e81da 100644
--- a/packages/common/package.json
+++ b/packages/common/package.json
@@ -1,6 +1,6 @@
{
"name": "@ps-analysis-tool/common",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "A package for common utilities that are being used in multiple packages",
"main": "./dist/index.js",
"types": "./dist-types/index.d.ts",
@@ -28,6 +28,6 @@
"tldts": "^6.0.14"
},
"devDependencies": {
- "devtools-protocol": "^0.0.1236148"
+ "devtools-protocol": "^0.0.1282316"
}
}
diff --git a/packages/common/src/constants/index.ts b/packages/common/src/constants/index.ts
index ff859b711..92c2b2764 100644
--- a/packages/common/src/constants/index.ts
+++ b/packages/common/src/constants/index.ts
@@ -14,5 +14,3 @@
* limitations under the License.
*/
export const UNKNOWN_FRAME_KEY = 'Unknown Frames';
-export const ORPHANED_COOKIE_KEY = 'Orphaned Cookies';
-export const UNMAPPED_COOKIE_KEY = 'Unmapped Cookies';
diff --git a/packages/common/src/cookies.types.ts b/packages/common/src/cookies.types.ts
index 3ad966c21..13ed47885 100644
--- a/packages/common/src/cookies.types.ts
+++ b/packages/common/src/cookies.types.ts
@@ -40,6 +40,10 @@ export type CookiesCount = {
total: number;
[key: string]: number;
};
+ exemptedCookies: {
+ total: number;
+ [key: string]: number;
+ };
};
export type CookieAnalytics = {
@@ -119,11 +123,11 @@ export type CookieData = {
inboundBlock: BLOCK_STATUS;
outboundBlock: BLOCK_STATUS;
};
+ exemptionReason?: Protocol.Network.CookieExemptionReason;
};
export type CookieTableData = CookieData & {
frameUrls?: string | string[];
- highlighted?: boolean;
isDomainInAllowList?: boolean;
};
@@ -162,11 +166,13 @@ export interface Legend {
count: number;
color: string;
countClassName: string;
+ onClick?: (title: string) => void;
}
export interface CookieStatsComponents {
legend: Legend[];
blockedCookiesLegend: Legend[];
+ exemptedCookiesLegend: Legend[];
firstParty: {
count: number;
color: string;
@@ -179,6 +185,10 @@ export interface CookieStatsComponents {
count: number;
color: string;
}[];
+ exempted: {
+ count: number;
+ color: string;
+ }[];
}
export interface FramesWithCookies {
@@ -209,6 +219,10 @@ export type CookieJsonDataType = {
requestUrls?: { [id: string]: string };
frameUrls?: { [id: string]: string };
isBlocked: boolean;
+ blockingStatus?: {
+ inboundBlock: BLOCK_STATUS;
+ outboundBlock: BLOCK_STATUS;
+ };
blockedReasons?: BlockedReason[];
};
@@ -230,3 +244,18 @@ export type CompleteJson = {
};
technologyData: TechnologyData[];
};
+
+export interface DataMapping {
+ title: string;
+ count: number;
+ data: {
+ count: number;
+ color: string;
+ }[];
+ onClick?: () => void;
+}
+
+export type FrameStateCreator = {
+ dataMapping: DataMapping[];
+ legend: Legend[];
+};
diff --git a/packages/common/src/data/cookieExemptionReason/exemptionReasons.ts b/packages/common/src/data/cookieExemptionReason/exemptionReasons.ts
new file mode 100644
index 000000000..a53e27ad9
--- /dev/null
+++ b/packages/common/src/data/cookieExemptionReason/exemptionReasons.ts
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//For source see https://source.chromium.org/chromium/chromium/src/+/main:third_party/devtools-frontend/src/front_end/core/sdk/NetworkRequest.ts
+const CookieExemptionReason = {
+ UserSetting: 'This cookie is allowed by user preference.',
+ TPCDMetadata:
+ 'This cookie is allowed by a third-party cookie deprecation trial grace period.',
+ TPCDDeprecationTrial:
+ 'This cookie is allowed by third-party cookie phaseout deprecation trial.',
+ TPCDHeuristics:
+ 'This cookie is allowed by third-party cookie phaseout heuristics.',
+ EnterprisePolicy: 'This cookie is allowed by Chrome Enterprise policy.',
+ StorageAccessAPI: 'This cookie is allowed by the Storage Access API.',
+ TopLevelStorageAccessAPI:
+ 'This cookie is allowed by the top-level Storage Access API.',
+ CorsOptIn: 'This cookie is allowed by CORS opt-in',
+};
+
+export default CookieExemptionReason;
diff --git a/packages/common/src/data/cookieExemptionReason/index.ts b/packages/common/src/data/cookieExemptionReason/index.ts
new file mode 100644
index 000000000..3628d84e8
--- /dev/null
+++ b/packages/common/src/data/cookieExemptionReason/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as cookieExemptionReason } from './exemptionReasons';
diff --git a/packages/common/src/data/index.ts b/packages/common/src/data/index.ts
new file mode 100644
index 000000000..62c0d39c7
--- /dev/null
+++ b/packages/common/src/data/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as cookieIssueDetails } from './cookieExclusionAndWarningReasons';
+export { cookieExemptionReason } from './cookieExemptionReason';
diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts
index 1ec04a46b..3bae5d459 100644
--- a/packages/common/src/index.ts
+++ b/packages/common/src/index.ts
@@ -26,7 +26,7 @@ export { default as calculateEffectiveExpiryDate } from './utils/calculateEffect
export { default as sanitizeCsvRecord } from './utils/sanitizeCsvRecord';
export { parseUrl } from './utils/parseUrl';
export { default as fetchLocalData } from './utils/fetchLocalData';
-export { default as cookieIssueDetails } from './data/cookieExclusionAndWarningReasons';
+export * from './data';
export { default as parseResponseReceivedExtraInfo } from './utils/parseResponseReceivedExtraInfo';
export { default as parseRequestWillBeSentExtraInfo } from './utils/parseRequestWillBeSentExtraInfo';
export { default as getDomainFromUrl } from './utils/getDomainFromUrl';
@@ -35,6 +35,7 @@ export { default as noop } from './utils/noop';
export { default as getDevToolWorker } from './worker/devToolWorker';
export { default as executeTaskInDevToolWorker } from './worker/executeTaskInDevToolWorker';
export { default as getValueByKey } from './utils/getValueByKey';
+export * from './utils/contextSelector';
export { default as addUTMParams } from './utils/addUTMParams';
export * from './worker/enums';
export * from './utils/generateReports';
diff --git a/packages/common/src/utils/contextSelector/createContext.ts b/packages/common/src/utils/contextSelector/createContext.ts
new file mode 100644
index 000000000..512a96cd7
--- /dev/null
+++ b/packages/common/src/utils/contextSelector/createContext.ts
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import { createContext as createContextOrig } from 'use-context-selector';
+
+const createContext = (defaultValue: T) => {
+ return createContextOrig(defaultValue);
+};
+
+export default createContext;
diff --git a/packages/common/src/utils/contextSelector/index.ts b/packages/common/src/utils/contextSelector/index.ts
new file mode 100644
index 000000000..7becbbca9
--- /dev/null
+++ b/packages/common/src/utils/contextSelector/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { default as useContextSelector } from './useContextSelector';
+export { default as createContext } from './createContext';
diff --git a/packages/extension/src/utils/shallowEqual.ts b/packages/common/src/utils/contextSelector/shallowEqual.ts
similarity index 83%
rename from packages/extension/src/utils/shallowEqual.ts
rename to packages/common/src/utils/contextSelector/shallowEqual.ts
index 49ae656e1..b5f270073 100644
--- a/packages/extension/src/utils/shallowEqual.ts
+++ b/packages/common/src/utils/contextSelector/shallowEqual.ts
@@ -24,6 +24,14 @@ export const shallowEqual = (a: unknown, b: unknown): boolean => {
}
if (Array.isArray(a) && Array.isArray(b)) {
+ if (
+ typeof a[0] === 'object' &&
+ typeof b[0] === 'object' &&
+ a.length === b.length
+ ) {
+ return a.every((item, index) => shallowEqualObjects(item, b[index]));
+ }
+
return shallowEqualArrays(a, b);
}
diff --git a/packages/common/src/utils/contextSelector/tests/shallowEqual.ts b/packages/common/src/utils/contextSelector/tests/shallowEqual.ts
new file mode 100644
index 000000000..1ebe6e611
--- /dev/null
+++ b/packages/common/src/utils/contextSelector/tests/shallowEqual.ts
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+
+/**
+ * Internal dependencies
+ */
+import { shallowEqual } from '../shallowEqual';
+
+describe('shallowEqual', () => {
+ it('should return true if the objects are equal', () => {
+ const a = { a: 1, b: 2 };
+ const b = { a: 1, b: 2 };
+ expect(shallowEqual(a, b)).toBe(true);
+ });
+
+ it('should return false if the objects are not equal', () => {
+ const a = { a: 1, b: 2 };
+ const b = { a: 1, b: 3 };
+ expect(shallowEqual(a, b)).toBe(false);
+ });
+
+ it('should return true if the arrays are equal', () => {
+ const a = [1, 2, 3];
+ const b = [1, 2, 3];
+ expect(shallowEqual(a, b)).toBe(true);
+ });
+
+ it('should return false if the arrays are not equal', () => {
+ const a = [1, 2, 3];
+ const b = [1, 2, 4];
+ expect(shallowEqual(a, b)).toBe(false);
+ });
+
+ it('should return true if the arrays of objects are equal', () => {
+ const a = [
+ { a: 1, b: 2 },
+ { a: 3, b: 4 },
+ ];
+ const b = [
+ { a: 1, b: 2 },
+ { a: 3, b: 4 },
+ ];
+ expect(shallowEqual(a, b)).toBe(true);
+ });
+
+ it('should return false if the arrays of objects are not equal', () => {
+ const a = [
+ { a: 1, b: 2 },
+ { a: 3, b: 4 },
+ ];
+ const b = [
+ { a: 1, b: 2 },
+ { a: 3, b: 5 },
+ ];
+ expect(shallowEqual(a, b)).toBe(false);
+ });
+
+ it('should return false if the arrays of objects are not equal', () => {
+ const a = [
+ { a: 1, b: 2 },
+ { a: 3, b: 4 },
+ ];
+ const b = [
+ { a: 1, b: 2 },
+ { a: 3, b: 5 },
+ ];
+ expect(shallowEqual(a, b)).toBe(false);
+ });
+});
diff --git a/packages/extension/src/utils/useContextSelector.ts b/packages/common/src/utils/contextSelector/useContextSelector.ts
similarity index 100%
rename from packages/extension/src/utils/useContextSelector.ts
rename to packages/common/src/utils/contextSelector/useContextSelector.ts
diff --git a/packages/common/src/utils/fetchLocalData.ts b/packages/common/src/utils/fetchLocalData.ts
index bf6742271..92cc955fc 100644
--- a/packages/common/src/utils/fetchLocalData.ts
+++ b/packages/common/src/utils/fetchLocalData.ts
@@ -26,10 +26,7 @@ const fetchLocalData = async (path: string) => {
return await response.json();
} catch (error) {
// eslint-disable-next-line no-console
- console.warn(
- `Failed to fetch local data from path: ${path}. Error:`,
- error
- );
+ console.log(`Failed to fetch local data from path: ${path}. Error:`, error);
return [];
}
diff --git a/packages/common/src/utils/filterCookiesByFrame.ts b/packages/common/src/utils/filterCookiesByFrame.ts
index b36a33b4f..458b15731 100644
--- a/packages/common/src/utils/filterCookiesByFrame.ts
+++ b/packages/common/src/utils/filterCookiesByFrame.ts
@@ -16,22 +16,17 @@
/**
* Internal dependencies.
*/
-import { CookieTableData } from '../cookies.types';
-
-interface Cookies {
- [key: string]: CookieTableData;
-}
-
+import { TabCookies } from '../cookies.types';
interface TabFrames {
[key: string]: { frameIds: number[] };
}
const filterCookiesByFrame = (
- cookies: Cookies | null,
+ cookies: TabCookies | null,
tabFrames: TabFrames | null,
frameUrl: string | null
) => {
- const frameFilteredCookies: { [key: string]: CookieTableData } = {};
+ const frameFilteredCookies: TabCookies = {};
if (!cookies || !frameUrl || !tabFrames || !tabFrames[frameUrl]) {
return Object.values(frameFilteredCookies);
}
diff --git a/packages/common/src/utils/generateReports/generateAllCookiesCSV.ts b/packages/common/src/utils/generateReports/generateAllCookiesCSV.ts
index 70161e40d..59bbae22c 100644
--- a/packages/common/src/utils/generateReports/generateAllCookiesCSV.ts
+++ b/packages/common/src/utils/generateReports/generateAllCookiesCSV.ts
@@ -21,7 +21,10 @@ import sanitizeCsvRecord from '../sanitizeCsvRecord';
/**
* Internal dependencies
*/
-import type { CompleteJson, CookieJsonDataType } from '../../cookies.types';
+import {
+ type CompleteJson,
+ type CookieJsonDataType,
+} from '../../cookies.types';
import calculateEffectiveExpiryDate from '../calculateEffectiveExpiryDate';
export const COOKIES_DATA_HEADER = [
@@ -37,7 +40,7 @@ export const COOKIES_DATA_HEADER = [
'Value',
'Path',
'Expires',
- 'Cookie Affected',
+ 'Issues',
'GDPRPortal',
];
diff --git a/packages/common/src/utils/generateReports/generateAffectedCookiesCSV.ts b/packages/common/src/utils/generateReports/generateCookiesWithIssuesCSV.ts
similarity index 79%
rename from packages/common/src/utils/generateReports/generateAffectedCookiesCSV.ts
rename to packages/common/src/utils/generateReports/generateCookiesWithIssuesCSV.ts
index 15e2cbff3..a1ec91685 100644
--- a/packages/common/src/utils/generateReports/generateAffectedCookiesCSV.ts
+++ b/packages/common/src/utils/generateReports/generateCookiesWithIssuesCSV.ts
@@ -17,11 +17,11 @@
/**
* Internal dependencies
*/
-import { CompleteJson, CookieJsonDataType } from '../../cookies.types';
+import type { CompleteJson, CookieJsonDataType } from '../../cookies.types';
import calculateEffectiveExpiryDate from '../calculateEffectiveExpiryDate';
import sanitizeCsvRecord from '../sanitizeCsvRecord';
-export const AFFECTED_COOKIES_DATA_HEADERS = [
+export const COOKIES_WITH_ISSUES_DATA_HEADERS = [
'Name',
'Scope',
'Domain',
@@ -37,23 +37,25 @@ export const AFFECTED_COOKIES_DATA_HEADERS = [
'GDPRPortal',
];
-const generateAffectedCookiesCSV = (siteAnalysisData: CompleteJson): string => {
+const generateCookiesWithIssuesCSV = (
+ siteAnalysisData: CompleteJson
+): string => {
const frameCookieDataMap = siteAnalysisData.cookieData;
- const affectedCookieMap: Map = new Map();
+ const CookieWithIssueMap: Map = new Map();
// More than one frame can use one cookie, need to make a map for getting unique entries.
Object.entries(frameCookieDataMap).forEach(([, { frameCookies }]) => {
Object.entries(frameCookies).forEach(([cookieKey, cookieData]) => {
if (cookieData.isBlocked) {
- affectedCookieMap.set(cookieKey, cookieData);
+ CookieWithIssueMap.set(cookieKey, cookieData);
}
});
});
let cookieRecords = '';
- for (const cookie of affectedCookieMap.values()) {
+ for (const cookie of CookieWithIssueMap.values()) {
//This should be in the same order as cookieDataHeader
const recordsArray = [
cookie.parsedCookie.name,
@@ -74,7 +76,7 @@ const generateAffectedCookiesCSV = (siteAnalysisData: CompleteJson): string => {
cookieRecords += recordsArray.join(',') + '\r\n';
}
- return AFFECTED_COOKIES_DATA_HEADERS.join(',') + '\r\n' + cookieRecords;
+ return COOKIES_WITH_ISSUES_DATA_HEADERS.join(',') + '\r\n' + cookieRecords;
};
-export default generateAffectedCookiesCSV;
+export default generateCookiesWithIssuesCSV;
diff --git a/packages/common/src/utils/generateReports/generateSummaryDataCSV.ts b/packages/common/src/utils/generateReports/generateSummaryDataCSV.ts
index c2c1cc501..218bbba32 100644
--- a/packages/common/src/utils/generateReports/generateSummaryDataCSV.ts
+++ b/packages/common/src/utils/generateReports/generateSummaryDataCSV.ts
@@ -37,11 +37,11 @@ const generateSummaryDataCSV = (siteAnalysisData: CompleteJson): string => {
let functionalCookies = 0;
let marketingCookies = 0;
let uncategorisedCookies = 0;
- let affectedCookies = 0;
- let affectedAnalyticsCookies = 0;
- let affectedFunctionalCookies = 0;
- let affectedMarketingCookies = 0;
- let affectedUncategorisedCookies = 0;
+ let cookiesWithIssues = 0;
+ let analyticsCookiesWithIssues = 0;
+ let functionalCookiesWithIssues = 0;
+ let marketingCookiesWithIssues = 0;
+ let uncategorisedCookiesWithIssues = 0;
for (const cookie of cookieMap.values()) {
if (cookie.isFirstParty) {
@@ -51,32 +51,32 @@ const generateSummaryDataCSV = (siteAnalysisData: CompleteJson): string => {
}
if (cookie.isBlocked) {
- affectedCookies += 1;
+ cookiesWithIssues += 1;
}
switch (cookie.analytics.category) {
case 'Analytics':
analyticsCookies += 1;
if (cookie.isBlocked) {
- affectedAnalyticsCookies += 1;
+ analyticsCookiesWithIssues += 1;
}
break;
case 'Functional':
functionalCookies += 1;
if (cookie.isBlocked) {
- affectedFunctionalCookies += 1;
+ functionalCookiesWithIssues += 1;
}
break;
case 'Marketing':
marketingCookies += 1;
if (cookie.isBlocked) {
- affectedMarketingCookies += 1;
+ marketingCookiesWithIssues += 1;
}
break;
case 'Uncategorized':
uncategorisedCookies += 1;
if (cookie.isBlocked) {
- affectedUncategorisedCookies += 1;
+ uncategorisedCookiesWithIssues += 1;
}
break;
default:
@@ -92,11 +92,11 @@ const generateSummaryDataCSV = (siteAnalysisData: CompleteJson): string => {
'Functional Cookies': functionalCookies,
'Marketing Cookies': marketingCookies,
'Uncategorized Cookies': uncategorisedCookies,
- 'Affected Cookies': affectedCookies,
- 'Affected Analytics Cookies': affectedAnalyticsCookies,
- 'Affected Functional Cookies': affectedFunctionalCookies,
- 'Affected Marketing Cookies': affectedMarketingCookies,
- 'Affected Uncategorized Cookies': affectedUncategorisedCookies,
+ 'Cookies With Issues': cookiesWithIssues,
+ 'Analytics Cookies With Issues': analyticsCookiesWithIssues,
+ 'Functional Cookies With Issues': functionalCookiesWithIssues,
+ 'Marketing Cookies With Issues': marketingCookiesWithIssues,
+ 'Uncategorized Cookies With Issues': uncategorisedCookiesWithIssues,
};
const CSVString = Object.entries(summary).reduce(
diff --git a/packages/common/src/utils/generateReports/index.ts b/packages/common/src/utils/generateReports/index.ts
index 12c0d45a3..75a64d39b 100644
--- a/packages/common/src/utils/generateReports/index.ts
+++ b/packages/common/src/utils/generateReports/index.ts
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-export { default as generateAffectedCookiesCSV } from './generateAffectedCookiesCSV';
+export { default as generateCookiesWithIssuesCSV } from './generateCookiesWithIssuesCSV';
export { default as generateAllCookiesCSV } from './generateAllCookiesCSV';
export { default as generateSummaryDataCSV } from './generateSummaryDataCSV';
export { default as generateTechnologyCSV } from './generateTechnologyCSV';
diff --git a/packages/common/src/utils/generateReports/tests/generateAffectedCookiesCSV.ts b/packages/common/src/utils/generateReports/tests/generateAffectedCookiesCSV.ts
index b44cb711d..74d8fc438 100644
--- a/packages/common/src/utils/generateReports/tests/generateAffectedCookiesCSV.ts
+++ b/packages/common/src/utils/generateReports/tests/generateAffectedCookiesCSV.ts
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-import generateAffectedCookiesCSV from '../generateAffectedCookiesCSV';
+import generateCookiesWithIssuesCSV from '../generateCookiesWithIssuesCSV';
import { mockData1 } from './data.mock';
-describe('generateAffectedCookiesCSV', () => {
- it('should create CSV string for affected cookies', () => {
- const CSVString = generateAffectedCookiesCSV(mockData1);
+describe('generateCookiesWithIssuesCSV', () => {
+ it('should create CSV string for cookies with issues', () => {
+ const CSVString = generateCookiesWithIssuesCSV(mockData1);
expect(CSVString.split('\r\n').filter((str) => str).length).toBe(4);
});
diff --git a/packages/common/src/utils/parseRequestWillBeSentExtraInfo.ts b/packages/common/src/utils/parseRequestWillBeSentExtraInfo.ts
index f434c6213..a599b60be 100644
--- a/packages/common/src/utils/parseRequestWillBeSentExtraInfo.ts
+++ b/packages/common/src/utils/parseRequestWillBeSentExtraInfo.ts
@@ -31,21 +31,23 @@ import isFirstParty from './isFirstParty';
/**
* Parses Network.requestWillBeSentExtraInfo to get extra information about a cookie.
- * @param {object} request Request to be parsed to get extra information about a cookie.
+ * @param {object} associatedCookies Cookies associated with the request being parsed.
* @param {object} cookieDB Cookie database to find analytics from.
* @param {object} requestMap An object for requestId to url.
* @param {string} tabUrl - The top-level URL (URL in the tab's address bar).
+ * @param {string} requestId - The requestId of the request being processed
* @returns {object} parsed cookies.
*/
export default function parseRequestWillBeSentExtraInfo(
- request: Protocol.Network.RequestWillBeSentExtraInfoEvent,
+ associatedCookies: Protocol.Network.RequestWillBeSentExtraInfoEvent['associatedCookies'],
cookieDB: CookieDatabase,
requestMap: { [requestId: string]: string },
- tabUrl: string
+ tabUrl: string,
+ requestId: string
) {
const cookies: CookieData[] = [];
- request.associatedCookies.forEach(({ blockedReasons, cookie }) => {
+ associatedCookies.forEach(({ blockedReasons, cookie, exemptionReason }) => {
const effectiveExpirationDate = calculateEffectiveExpiryDate(
cookie.expires
);
@@ -53,8 +55,8 @@ export default function parseRequestWillBeSentExtraInfo(
let domain,
url = '';
- if (requestMap && requestMap[request?.requestId]) {
- url = requestMap[request?.requestId] ?? '';
+ if (requestMap && requestMap[requestId]) {
+ url = requestMap[requestId] ?? '';
}
if (cookie?.domain) {
@@ -75,7 +77,7 @@ export default function parseRequestWillBeSentExtraInfo(
requestEvents: [
{
type: REQUEST_EVENT.CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO,
- requestId: request.requestId,
+ requestId,
url: url,
blocked: blockedReasons.length !== 0,
timeStamp: Date.now(),
@@ -89,6 +91,7 @@ export default function parseRequestWillBeSentExtraInfo(
headerType: 'request' as CookieData['headerType'],
isFirstParty: isFirstParty(domain, tabUrl),
frameIdList: [],
+ exemptionReason: exemptionReason ? exemptionReason : undefined,
};
cookies.push(singleCookie);
diff --git a/packages/common/src/utils/parseResponseReceivedExtraInfo.ts b/packages/common/src/utils/parseResponseReceivedExtraInfo.ts
index c5a6005f1..a43d6d706 100644
--- a/packages/common/src/utils/parseResponseReceivedExtraInfo.ts
+++ b/packages/common/src/utils/parseResponseReceivedExtraInfo.ts
@@ -33,26 +33,33 @@ import isFirstParty from './isFirstParty';
/**
* Parse Network.responseReceivedExtraInfo for extra information about a cookie.
- * @param {object} response Response to be parsed to get extra information about a cookie.
+ * @param {object} headers Headers of resonse to be parsed to get extra information about a cookie.
+ * @param {object} blockedCookies Blocked Cookies associated with the response being parsed.
+ * @param {object} exemptedCookies Blocked Cookies associated with the response being parsed.
+ * @param {string|undefined} cookiePartitionKey Partittion key for the response.
* @param {object} requestMap An object for requestId to url.
* @param {string} tabUrl - The top-level URL (URL in the tab's address bar).
* @param {object} cookieDB Cookie database to find analytics from.
+ * @param {string} requestId - The requestId of the request being processed
* @returns {object} parsed cookies.
*/
export default function parseResponseReceivedExtraInfo(
- response: Protocol.Network.ResponseReceivedExtraInfoEvent,
+ headers: Protocol.Network.ResponseReceivedExtraInfoEvent['headers'],
+ blockedCookies: Protocol.Network.ResponseReceivedExtraInfoEvent['blockedCookies'],
+ exemptedCookies: Protocol.Network.ResponseReceivedExtraInfoEvent['exemptedCookies'],
+ cookiePartitionKey: Protocol.Network.ResponseReceivedExtraInfoEvent['cookiePartitionKey'],
requestMap: { [requestId: string]: string },
tabUrl: string,
- cookieDB: CookieDatabase
+ cookieDB: CookieDatabase,
+ requestId: string
) {
const cookies: CookieData[] = [];
- const responseToParse =
- response.headers['set-cookie'] ?? response.headers['Set-Cookie'];
+ const responseToParse = headers['set-cookie'] ?? headers['Set-Cookie'];
responseToParse?.split('\n').forEach((headerLine: string) => {
let parsedCookie: CookieData['parsedCookie'] = parse(headerLine);
- const blockedCookie = response.blockedCookies.find((c) => {
+ const blockedCookie = blockedCookies.find((c) => {
if (c.cookie) {
return c.cookie?.name === parsedCookie.name;
} else {
@@ -61,6 +68,13 @@ export default function parseResponseReceivedExtraInfo(
}
});
+ const exemptedCookie = exemptedCookies?.find((c) => {
+ if (c.cookie) {
+ return c.cookie?.name === parsedCookie.name;
+ }
+ return false;
+ });
+
const effectiveExpirationDate = calculateEffectiveExpiryDate(
parsedCookie.expires
);
@@ -68,15 +82,15 @@ export default function parseResponseReceivedExtraInfo(
if (headerLine.toLowerCase().includes('partitioned')) {
parsedCookie = {
...parsedCookie,
- partitionKey: response?.cookiePartitionKey,
+ partitionKey: cookiePartitionKey,
};
}
let domain,
url = '';
- if (requestMap && requestMap[response?.requestId]) {
- url = requestMap[response?.requestId] ?? '';
+ if (requestMap && requestMap[requestId]) {
+ url = requestMap[requestId] ?? '';
}
if (parsedCookie?.domain) {
@@ -99,7 +113,7 @@ export default function parseResponseReceivedExtraInfo(
responseEvents: [
{
type: RESPONSE_EVENT.CDP_RESPONSE_RECEIVED_EXTRA_INFO,
- requestId: response.requestId,
+ requestId,
url: url,
blocked: blockedCookie ? true : false,
timeStamp: Date.now(),
@@ -113,6 +127,7 @@ export default function parseResponseReceivedExtraInfo(
isFirstParty: isFirstParty(domain, tabUrl),
headerType: 'response' as CookieData['headerType'],
frameIdList: [],
+ exemptionReason: exemptedCookie?.exemptionReason,
};
cookies.push(singleCookie);
diff --git a/packages/design-system/package.json b/packages/design-system/package.json
index da22940f8..7d9530651 100644
--- a/packages/design-system/package.json
+++ b/packages/design-system/package.json
@@ -1,6 +1,6 @@
{
"name": "@ps-analysis-tool/design-system",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "A package for presentational components that are being used in multiple packages",
"main": "./src/index.ts",
"source":"./src/index.ts",
diff --git a/packages/design-system/src/components/button/index.tsx b/packages/design-system/src/components/button/index.tsx
index 41e5ce6dc..35f1c3033 100644
--- a/packages/design-system/src/components/button/index.tsx
+++ b/packages/design-system/src/components/button/index.tsx
@@ -21,100 +21,61 @@ import React from 'react';
interface ButtonProps {
text: string | React.ReactNode;
+ title?: string;
name?: string;
onClick?: () => void;
loading?: boolean;
type?: 'button' | 'submit' | 'reset';
variant?: 'primary' | 'secondary' | 'danger' | 'small' | 'large';
extraClasses?: string;
+ disabled?: boolean;
}
const Button = ({
+ title = '',
text,
name = 'button',
onClick = undefined,
type = 'button',
variant = 'primary',
extraClasses = '',
+ disabled = false,
}: ButtonProps) => {
- switch (variant) {
- case 'small':
- return (
-
- {text}
-
- );
- case 'large':
- return (
-
- {text}
-
- );
- case 'primary':
- return (
-
- {text}
-
- );
- case 'secondary':
- return (
-
- {text}
-
- );
- case 'danger':
- return (
-
- {text}
-
- );
- default:
- return <>>;
- }
+ return (
+
+ {text}
+
+ );
};
export default Button;
diff --git a/packages/design-system/src/components/circlePieChart/index.tsx b/packages/design-system/src/components/circlePieChart/index.tsx
index 077a49c50..43107ca6c 100644
--- a/packages/design-system/src/components/circlePieChart/index.tsx
+++ b/packages/design-system/src/components/circlePieChart/index.tsx
@@ -32,6 +32,8 @@ interface CirclePieChartProps {
title?: string;
fallbackText?: string;
infoIconClassName?: string;
+ centerTitleExtraClasses?: string;
+ pieChartExtraClasses?: string;
}
export const MAX_COUNT = 999;
@@ -41,16 +43,18 @@ const CirclePieChart = ({
data,
title,
infoIconClassName = '',
+ centerTitleExtraClasses = '',
+ pieChartExtraClasses = '',
}: CirclePieChartProps) => {
const centerTitleClasses = centerCount <= MAX_COUNT ? 'text-2xl' : 'text-l';
return (
- <>
+
{centerCount <= 0 ? (
) : (
-
+
{centerCount <= MAX_COUNT ? centerCount : MAX_COUNT + '+'}
@@ -85,7 +90,7 @@ const CirclePieChart = ({
)}
)}
- >
+
);
};
diff --git a/packages/design-system/src/components/cookieDetails/details.tsx b/packages/design-system/src/components/cookieDetails/details.tsx
index dc83d889d..8087c99ce 100644
--- a/packages/design-system/src/components/cookieDetails/details.tsx
+++ b/packages/design-system/src/components/cookieDetails/details.tsx
@@ -21,6 +21,8 @@ import React, { useState } from 'react';
import classNames from 'classnames';
import {
BLOCK_STATUS,
+ CookieData,
+ cookieExemptionReason,
cookieIssueDetails,
type CookieTableData,
} from '@ps-analysis-tool/common';
@@ -87,6 +89,21 @@ const Details = ({ selectedCookie, isUsingCDP }: DetailsProps) => {
return (
+ {selectedCookie.exemptionReason &&
+ selectedCookie.exemptionReason.toLowerCase() !== 'none' && (
+
+
+ Exemption Reason
+
+
+ {
+ cookieExemptionReason[
+ selectedCookie.exemptionReason as CookieData['exemptionReason']
+ ]
+ }
+
+
+ )}
{selectedCookie.isDomainInAllowList && (
@@ -100,19 +117,17 @@ const Details = ({ selectedCookie, isUsingCDP }: DetailsProps) => {
)}
- {(outboundBlock || inboundBlock) &&
- hasValidBlockedReason &&
- isUsingCDP && (
- <>
-
- Blocked Reason
-
-
- >
- )}
+ {hasValidBlockedReason && isUsingCDP && (
+ <>
+
+ Blocked Reason
+
+
+ >
+ )}
{selectedCookie?.blockingStatus?.inboundBlock ===
BLOCK_STATUS.BLOCKED_IN_SOME_EVENTS &&
diff --git a/packages/design-system/src/components/cookieTable/index.tsx b/packages/design-system/src/components/cookieTable/index.tsx
index eb7025866..92465b00f 100644
--- a/packages/design-system/src/components/cookieTable/index.tsx
+++ b/packages/design-system/src/components/cookieTable/index.tsx
@@ -29,25 +29,19 @@ import { CookieTableData, getCookieKey } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import {
- Table,
- TableColumn,
- TableData,
- TableFilter,
- TableRow,
- useTable,
-} from '../table';
+import { Table, TableColumn, TableData, TableFilter, TableRow } from '../table';
+import { TableProvider } from '../table/useTable/provider';
+import { conditionalTableRowClassesHandler, exportCookies } from './utils';
interface CookieTableProps {
- useIsBlockedToHighlight?: boolean;
+ queryIsBlockedToHighlight?: boolean;
data: TableData[];
tableColumns: TableColumn[];
tableFilters?: TableFilter;
tableSearchKeys?: string[];
tablePersistentSettingsKey?: string;
+ isFiltersSidebarOpen?: boolean;
selectedFrame: string | null;
- showTopBar?: boolean;
- hideExport?: boolean;
selectedFrameCookie: {
[frame: string]: CookieTableData | null;
} | null;
@@ -56,11 +50,12 @@ interface CookieTableProps {
[frame: string]: CookieTableData | null;
} | null
) => void;
- extraInterfaceToTopBar?: React.ReactNode;
+ extraInterfaceToTopBar?: () => React.JSX.Element;
onRowContextMenu?: (
e: React.MouseEvent
,
row: TableRow
) => void;
+ hideExport?: boolean;
}
const CookieTable = forwardRef<
@@ -70,19 +65,19 @@ const CookieTable = forwardRef<
CookieTableProps
>(function CookieTable(
{
- useIsBlockedToHighlight = false,
+ queryIsBlockedToHighlight = true,
tableColumns,
tableFilters,
tableSearchKeys,
tablePersistentSettingsKey,
data: cookies,
- showTopBar,
- hideExport = false,
+ isFiltersSidebarOpen,
selectedFrame,
selectedFrameCookie,
setSelectedFrameCookie,
extraInterfaceToTopBar,
onRowContextMenu,
+ hideExport,
}: CookieTableProps,
ref
) {
@@ -108,6 +103,22 @@ const CookieTable = forwardRef<
[selectedFrame, setSelectedFrameCookie]
);
+ const onRowContextMenuHandler = useCallback(
+ (e: React.MouseEvent, row: TableRow) => {
+ onRowContextMenu?.(e, row);
+ onRowClick(row?.originalData);
+ },
+ [onRowClick, onRowContextMenu]
+ );
+
+ const getRowObjectKey = useCallback(
+ (row: TableRow) =>
+ getCookieKey(
+ (row?.originalData as CookieTableData).parsedCookie
+ ) as string,
+ []
+ );
+
useImperativeHandle(
ref,
() => {
@@ -120,18 +131,43 @@ const CookieTable = forwardRef<
[onRowClick]
);
- const selectedKey = useMemo(
- () => Object.values(selectedFrameCookie ?? {})[0],
- [selectedFrameCookie]
+ const selectedKey = useMemo(() => {
+ const key = Object.values(selectedFrameCookie ?? {})[0];
+
+ return key === null ? null : getCookieKey(key?.parsedCookie);
+ }, [selectedFrameCookie]);
+
+ const _conditionalTableRowClassesHandler = useCallback(
+ (row: TableRow, isRowFocused: boolean, rowIndex: number) => {
+ return conditionalTableRowClassesHandler(
+ row,
+ isRowFocused,
+ rowIndex,
+ selectedKey,
+ queryIsBlockedToHighlight
+ );
+ },
+ [selectedKey, queryIsBlockedToHighlight]
);
- const table = useTable({
- tableColumns,
- data: cookies,
- tableFilterData: tableFilters,
- tableSearchKeys,
- tablePersistentSettingsKey,
- });
+ const hasVerticalBar = useCallback((row: TableRow) => {
+ const isDomainInAllowList = (row.originalData as CookieTableData)
+ ?.isDomainInAllowList;
+ return Boolean(isDomainInAllowList);
+ }, []);
+
+ const isRowSelected = useCallback(
+ (cookie: TableData | null) => {
+ const _cookie = cookie as CookieTableData;
+ if (!_cookie) {
+ return true;
+ }
+
+ const tableCookieKey = getCookieKey(_cookie.parsedCookie);
+ return tableCookieKey === selectedKey;
+ },
+ [selectedKey]
+ );
useEffect(() => {
window.addEventListener('resize', () => forceUpdate());
@@ -140,31 +176,29 @@ const CookieTable = forwardRef<
};
}, []);
+ // TODO: Move TableProvider and logic to one level up in extension and cli-dashboard, for allowing modularity.
return (
-
- getCookieKey(
- (row?.originalData as CookieTableData).parsedCookie
- ) as string
- }
+ ,
- row: TableRow
- ) => {
- onRowContextMenu?.(e, row);
- onRowClick(row?.originalData);
- }}
- />
+ onRowContextMenu={onRowContextMenuHandler}
+ getRowObjectKey={getRowObjectKey}
+ conditionalTableRowClassesHandler={_conditionalTableRowClassesHandler}
+ exportTableData={!hideExport ? exportCookies : undefined}
+ hasVerticalBar={hasVerticalBar}
+ isRowSelected={isRowSelected}
+ >
+
+
);
});
diff --git a/packages/design-system/src/components/cookieTable/tests/index.tsx b/packages/design-system/src/components/cookieTable/tests/index.tsx
index 53e957107..994852886 100644
--- a/packages/design-system/src/components/cookieTable/tests/index.tsx
+++ b/packages/design-system/src/components/cookieTable/tests/index.tsx
@@ -315,9 +315,12 @@ describe('CookieTable', () => {
const test2Filter = await screen.findByText('test2Filter');
act(() => fireEvent.click(test2Filter));
+ const test3Filter = await screen.findByText('test3Filter');
+ act(() => fireEvent.click(test3Filter));
+
await waitFor(() => {
const rows = screen.getAllByTestId('body-row');
- expect(rows.length).toBe(2);
+ expect(rows.length).toBe(3);
});
const clearFiltersButton = await screen.findByText('Clear all');
diff --git a/packages/design-system/src/components/cookieTable/utils/conditionalTableRowClassesHandler.ts b/packages/design-system/src/components/cookieTable/utils/conditionalTableRowClassesHandler.ts
new file mode 100644
index 000000000..71821b47d
--- /dev/null
+++ b/packages/design-system/src/components/cookieTable/utils/conditionalTableRowClassesHandler.ts
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {
+ BLOCK_STATUS,
+ CookieTableData,
+ getCookieKey,
+} from '@ps-analysis-tool/common';
+import classnames from 'classnames';
+
+import { TableRow } from '../../table';
+
+// eslint-disable-next-line complexity
+const conditionalTableRowClassesHandler = (
+ row: TableRow,
+ isRowFocused: boolean,
+ rowIndex: number,
+ selectedKey: string | null,
+ queryIsBlockedToHighlight: boolean
+) => {
+ const rowKey = getCookieKey(
+ (row?.originalData as CookieTableData).parsedCookie
+ ) as string;
+ const isBlocked = queryIsBlockedToHighlight
+ ? (row.originalData as CookieTableData)?.isBlocked
+ : (row.originalData as CookieTableData)?.blockingStatus?.inboundBlock !==
+ BLOCK_STATUS.NOT_BLOCKED ||
+ (row.originalData as CookieTableData)?.blockingStatus?.outboundBlock !==
+ BLOCK_STATUS.NOT_BLOCKED;
+ const isDomainInAllowList = (row.originalData as CookieTableData)
+ ?.isDomainInAllowList;
+
+ const tableRowClassName = classnames(
+ isBlocked &&
+ (rowKey !== selectedKey
+ ? rowIndex % 2
+ ? 'dark:bg-flagged-row-even-dark bg-flagged-row-even-light'
+ : 'dark:bg-flagged-row-odd-dark bg-flagged-row-odd-light'
+ : isRowFocused
+ ? 'bg-selection-yellow-dark dark:bg-selection-yellow-light'
+ : 'bg-royal-blue text-white dark:bg-medium-persian-blue dark:text-chinese-silver'),
+ isDomainInAllowList &&
+ !isBlocked &&
+ (rowKey !== selectedKey
+ ? rowIndex % 2
+ ? 'dark:bg-jungle-green-dark bg-leaf-green-dark'
+ : 'dark:bg-jungle-green-light bg-leaf-green-light'
+ : isRowFocused
+ ? 'bg-selection-green-dark dark:bg-selection-green-light'
+ : 'bg-royal-blue text-white dark:bg-medium-persian-blue dark:text-chinese-silver')
+ );
+
+ return tableRowClassName;
+};
+
+export default conditionalTableRowClassesHandler;
diff --git a/packages/design-system/src/components/cookieTable/utils/exportCookies.ts b/packages/design-system/src/components/cookieTable/utils/exportCookies.ts
new file mode 100644
index 000000000..2c88458b8
--- /dev/null
+++ b/packages/design-system/src/components/cookieTable/utils/exportCookies.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import { CookieTableData } from '@ps-analysis-tool/common';
+import { saveAs } from 'file-saver';
+
+/**
+ * Internal dependencies
+ */
+import { TableRow } from '../../table';
+import { generateCookieTableCSV } from '../../table/utils';
+
+const exportCookies = (rows: TableRow[]) => {
+ const _cookies = rows.map(({ originalData }) => originalData);
+ if (_cookies.length > 0 && 'parsedCookie' in _cookies[0]) {
+ const csvTextBlob = generateCookieTableCSV(_cookies as CookieTableData[]);
+ saveAs(csvTextBlob, 'Cookies Report.csv');
+ }
+};
+
+export default exportCookies;
diff --git a/packages/design-system/src/components/cookieTable/utils/index.ts b/packages/design-system/src/components/cookieTable/utils/index.ts
new file mode 100644
index 000000000..cf16d9027
--- /dev/null
+++ b/packages/design-system/src/components/cookieTable/utils/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { default as exportCookies } from './exportCookies';
+export { default as conditionalTableRowClassesHandler } from './conditionalTableRowClassesHandler';
diff --git a/packages/design-system/src/components/cookiesLanding/cookieLandingHeaderContainer.tsx b/packages/design-system/src/components/cookiesLanding/cookiesLandingWrapper.tsx
similarity index 64%
rename from packages/design-system/src/components/cookiesLanding/cookieLandingHeaderContainer.tsx
rename to packages/design-system/src/components/cookiesLanding/cookiesLandingWrapper.tsx
index 6db89b044..631662f19 100644
--- a/packages/design-system/src/components/cookiesLanding/cookieLandingHeaderContainer.tsx
+++ b/packages/design-system/src/components/cookiesLanding/cookiesLandingWrapper.tsx
@@ -22,26 +22,44 @@ import React from 'react';
* Internal dependencies.
*/
import LandingHeader, { type DataMapping } from './landingHeader';
+import { InfoIcon } from '../../icons';
-export interface CookiesLandingContainerProps {
+export interface CookiesLandingWrapperProps {
dataMapping?: DataMapping[];
+ infoIconTitle?: string | React.ReactNode;
showLandingHeader?: boolean;
testId?: string | null;
children?: React.ReactNode;
description?: React.ReactNode;
}
-const CookiesLandingContainer = ({
+const CookiesLandingWrapper = ({
dataMapping = [],
+ infoIconTitle = '',
showLandingHeader = true,
testId = 'cookie-landing-insights',
description = '',
children,
-}: CookiesLandingContainerProps) => {
+}: CookiesLandingWrapperProps) => {
return (
- {showLandingHeader &&
}
+
+ {showLandingHeader &&
}
+ {Boolean(infoIconTitle) && (
+
+
+
+
+
+ {infoIconTitle}
+
+
+ )}
+
{description && (
@@ -57,4 +75,4 @@ const CookiesLandingContainer = ({
);
};
-export default CookiesLandingContainer;
+export default CookiesLandingWrapper;
diff --git a/packages/design-system/src/components/cookiesLanding/cookiesMatrix/index.tsx b/packages/design-system/src/components/cookiesLanding/cookiesMatrix/index.tsx
index 102abd0cb..88247388c 100644
--- a/packages/design-system/src/components/cookiesLanding/cookiesMatrix/index.tsx
+++ b/packages/design-system/src/components/cookiesLanding/cookiesMatrix/index.tsx
@@ -16,7 +16,7 @@
/**
* External dependencies.
*/
-import React, { useState } from 'react';
+import React from 'react';
import {
type TabCookies,
type TabFrames,
@@ -26,13 +26,10 @@ import {
/**
* Internal dependencies
*/
-import Matrix from '../../matrix';
import type { MatrixComponentProps } from '../../matrix/matrixComponent';
-import { InfoIcon } from '../../../icons';
-import MatrixComponentHorizontal, {
- type MatrixComponentHorizontalProps,
-} from '../../matrix/matrixComponent/matrixComponentHorizontal';
+import { type MatrixComponentHorizontalProps } from '../../matrix/matrixComponent/matrixComponentHorizontal';
import { LEGEND_DESCRIPTION } from '../../../constants';
+import MatrixContainer from '../../matrixContainer';
interface CookiesMatrixProps {
tabCookies: TabCookies | null;
@@ -42,14 +39,13 @@ interface CookiesMatrixProps {
description?: string;
showHorizontalMatrix?: boolean;
showMatrix?: boolean;
- showInfoIcon?: boolean;
count?: number | null;
associatedCookiesCount?: number | null;
allowExpand?: boolean;
highlightTitle?: boolean;
capitalizeTitle?: boolean;
- infoIconTitle?: string;
matrixHorizontalData?: MatrixComponentHorizontalProps[] | null;
+ infoIconTitle?: string;
}
const CookiesMatrix = ({
@@ -60,16 +56,14 @@ const CookiesMatrix = ({
description = '',
showHorizontalMatrix = true,
showMatrix = true,
- showInfoIcon = true,
count = null,
associatedCookiesCount = null,
allowExpand = true,
highlightTitle = false,
capitalizeTitle = false,
matrixHorizontalData = null,
- infoIconTitle = 'Cookies must be analyzed on a new, clean Chrome profile for an accurate report.',
+ infoIconTitle,
}: CookiesMatrixProps) => {
- const [isExpanded, setIsExpanded] = useState(false);
const dataComponents: MatrixComponentProps[] = [];
componentData.forEach((component) => {
@@ -78,7 +72,6 @@ const CookiesMatrix = ({
...component,
description: legendDescription,
title: component.label,
- isExpanded,
containerClasses: '',
});
});
@@ -87,13 +80,12 @@ const CookiesMatrix = ({
const framesWithCookies = filterFramesWithCookies(tabCookies, tabFrames);
const matrixHorizontalComponents = matrixHorizontalData
- ? matrixHorizontalData.map((data) => ({ ...data, expand: isExpanded }))
+ ? matrixHorizontalData
: [
{
title: 'Number of Frames',
description: 'Number of unique frames found across the page(s).',
count: totalFrames,
- expand: isExpanded,
},
{
title: 'Number of Frames with Associated Cookies',
@@ -104,54 +96,25 @@ const CookiesMatrix = ({
: framesWithCookies
? Object.keys(framesWithCookies).length
: 0,
- expand: isExpanded,
},
];
+
return (
-
-
-
-
- {title}
- {showInfoIcon && (
-
-
-
- )}
- {count !== null && : {Number(count) || 0} }
-
-
- {description}
-
-
- {allowExpand && (
-
- setIsExpanded((state) => !state)}>
- {isExpanded ? 'Collapse View' : 'Expand View'}
-
-
- )}
-
- {showMatrix &&
}
-
- {showHorizontalMatrix && (
-
- {matrixHorizontalComponents.map(
- (matrixHorizontalComponent, index) => (
-
- )
- )}
-
- )}
+
);
};
diff --git a/packages/design-system/src/components/cookiesLanding/cookiesMatrix/tests/cookieMatrix.tsx b/packages/design-system/src/components/cookiesLanding/cookiesMatrix/tests/cookieMatrix.tsx
index 79e43674f..7c1f2c681 100644
--- a/packages/design-system/src/components/cookiesLanding/cookiesMatrix/tests/cookieMatrix.tsx
+++ b/packages/design-system/src/components/cookiesLanding/cookiesMatrix/tests/cookieMatrix.tsx
@@ -17,7 +17,7 @@
* External dependencies.
*/
import React from 'react';
-import { render } from '@testing-library/react';
+import { screen, render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
/**
@@ -28,14 +28,14 @@ import mockResponse from '../../../../test-data/cookieMockData';
import cookiesStatsComponents from '../../../../test-data/cookiesStatsComponents';
describe('CookiesMatrix', () => {
- it('should render the cookies insights', () => {
+ it('should render the cookies insights', async () => {
const tabCookies = mockResponse.tabCookies;
const tabFrames = mockResponse.tabFrames;
const title = 'Title';
- const { getByTestId } = render(
+ const { getByTestId, findByText, findAllByText } = render(
{
);
expect(getByTestId(`cookies-matrix-${title}`)).toBeInTheDocument();
+
+ const expandButton = await screen.findByTestId('expand-button');
+
+ expect(expandButton).toBeInTheDocument();
+
+ expandButton.click();
+
+ expect(await findByText('Functional')).toBeInTheDocument();
+ expect((await findAllByText('1'))[0]).toHaveClass(
+ cookiesStatsComponents.legend[0].countClassName
+ );
});
});
diff --git a/packages/design-system/src/components/cookiesLanding/index.tsx b/packages/design-system/src/components/cookiesLanding/index.tsx
index cf406c2a6..b64405b98 100644
--- a/packages/design-system/src/components/cookiesLanding/index.tsx
+++ b/packages/design-system/src/components/cookiesLanding/index.tsx
@@ -17,157 +17,27 @@
* External dependencies.
*/
import React from 'react';
-import type { TabCookies, TabFrames } from '@ps-analysis-tool/common';
-/**
- * Internal dependencies.
- */
-import MessageBox from '../messageBox';
-import { type DataMapping } from './landingHeader';
-import CookiesMatrix from './cookiesMatrix';
-import CookiesLandingContainer from './cookieLandingHeaderContainer';
-import {
- prepareCookieStatsComponents,
- prepareCookiesCount,
- prepareFrameStatsComponent,
-} from '../../utils';
+export type CookiesLandingSection = {
+ name: string;
+ link: string;
+ panel: {
+ Element: ((props: any) => React.JSX.Element) | React.NamedExoticComponent;
+ props?: Record;
+ };
+};
interface CookiesLandingProps {
- tabFrames: TabFrames | null;
- tabCookies: TabCookies | null;
children?: React.ReactNode;
- showInfoIcon?: boolean;
- showBlockedInfoIcon?: boolean;
- showHorizontalMatrix?: boolean;
- associatedCookiesCount?: number | null;
- showMessageBoxBody?: boolean;
- showBlockedCookiesSection?: boolean;
- additionalComponents?: {
- [key: string]: React.FunctionComponent;
- };
- showFramesSection?: boolean;
- description?: React.ReactNode;
- cookieClassificationTitle?: string;
}
-const CookiesLanding = ({
- tabCookies,
- tabFrames,
- children,
- showInfoIcon = true,
- showBlockedInfoIcon = true,
- associatedCookiesCount = null,
- showMessageBoxBody = true,
- showBlockedCookiesSection = false,
- showFramesSection = false,
- showHorizontalMatrix = false,
- description = '',
- additionalComponents = {},
- cookieClassificationTitle,
-}: CookiesLandingProps) => {
- const cookieStats = prepareCookiesCount(tabCookies);
- const cookiesStatsComponents = prepareCookieStatsComponents(cookieStats);
- const frameStateCreator = prepareFrameStatsComponent(tabFrames, tabCookies);
- const cookieClassificationDataMapping: DataMapping[] = [
- {
- title: 'Total cookies',
- count: cookieStats.total,
- data: cookiesStatsComponents.legend,
- },
- {
- title: '1st party cookies',
- count: cookieStats.firstParty.total,
- data: cookiesStatsComponents.firstParty,
- },
- {
- title: '3rd party cookies',
- count: cookieStats.thirdParty.total,
- data: cookiesStatsComponents.thirdParty,
- },
- ];
-
- const blockedCookieDataMapping: DataMapping[] = [
- {
- title: 'Blocked cookies',
- count: cookieStats.blockedCookies.total,
- data: cookiesStatsComponents.blocked,
- },
- ];
-
+const CookiesLanding = ({ children }: CookiesLandingProps) => {
return (
-
- {!cookieStats ||
- (cookieStats?.firstParty.total === 0 &&
- cookieStats?.thirdParty.total === 0 && (
-
- ))}
-
-
- {showBlockedCookiesSection && (
-
- {cookiesStatsComponents.blockedCookiesLegend.length > 0 && (
- <>
-
- >
- )}
- {children && {children}
}
-
- )}
- {/* TODO: This is not scalable. Refactor code so that components can be added from the the extension or dashboard package. */}
- {Boolean(Object.keys(additionalComponents).length) &&
- Object.keys(additionalComponents).map((key: string) => {
- const Component = additionalComponents[key];
- return
;
- })}
- {showFramesSection && (
-
-
-
- )}
+ {children}
);
};
diff --git a/packages/design-system/src/components/cookiesLanding/landingHeader/index.tsx b/packages/design-system/src/components/cookiesLanding/landingHeader/index.tsx
index 5123927a4..d09fa7ee2 100644
--- a/packages/design-system/src/components/cookiesLanding/landingHeader/index.tsx
+++ b/packages/design-system/src/components/cookiesLanding/landingHeader/index.tsx
@@ -18,15 +18,8 @@
*/
import React from 'react';
import { CirclePieChart } from '@ps-analysis-tool/design-system';
-
-export interface DataMapping {
- title: string;
- count: number;
- data: {
- count: number;
- color: string;
- }[];
-}
+import { DataMapping } from '@ps-analysis-tool/common';
+import classnames from 'classnames';
interface LandingHeaderProps {
dataMapping?: DataMapping[];
@@ -36,20 +29,40 @@ const LandingHeader = ({ dataMapping = [] }: LandingHeaderProps) => {
return (
{dataMapping.map((circleData, index) => {
return (
-
-
+
+ {
+ circleData.onClick?.();
+ }}
+ >
+
+
);
})}
diff --git a/packages/design-system/src/components/cookiesLanding/landingHeader/tests/landingHeader.tsx b/packages/design-system/src/components/cookiesLanding/landingHeader/tests/landingHeader.tsx
index 0ba8877bf..b2947463a 100644
--- a/packages/design-system/src/components/cookiesLanding/landingHeader/tests/landingHeader.tsx
+++ b/packages/design-system/src/components/cookiesLanding/landingHeader/tests/landingHeader.tsx
@@ -17,7 +17,7 @@
* External dependencies.
*/
import React from 'react';
-import { render } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
/**
@@ -46,8 +46,10 @@ describe('LandingHeader', () => {
data: [...cookiesStatsComponents.thirdParty],
},
];
- const { getByTestId } = render(
);
+ render(
);
- expect(getByTestId('cookies-landing-header')).toBeInTheDocument();
+ expect(screen.getByTestId('cookies-landing-header')).toBeInTheDocument();
+ expect(screen.getByText('Total Cookies')).toBeInTheDocument();
+ expect(screen.getByText('999+')).toBeInTheDocument();
});
});
diff --git a/packages/design-system/src/components/cookiesLanding/tests/useFiltersMapping.tsx b/packages/design-system/src/components/cookiesLanding/tests/useFiltersMapping.tsx
new file mode 100644
index 000000000..e78b3c582
--- /dev/null
+++ b/packages/design-system/src/components/cookiesLanding/tests/useFiltersMapping.tsx
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { TabFrames } from '@ps-analysis-tool/common';
+import { renderHook } from '@testing-library/react';
+import useFiltersMapping from '../useFiltersMapping';
+import { useSidebar } from '../../sidebar/useSidebar';
+
+jest.mock('../../sidebar/useSidebar', () => ({
+ useSidebar: jest.fn(),
+}));
+const mockUseSidebar = useSidebar as jest.Mock;
+
+describe('useFiltersMapping', () => {
+ it('shoule return correct query object', () => {
+ // Arrange
+ const tabFrames = {
+ frame1: {
+ frameIds: [],
+ },
+ frame2: {
+ frameIds: [],
+ },
+ } as TabFrames;
+ const updateSelectedItemKey = jest.fn();
+
+ mockUseSidebar.mockReturnValue(updateSelectedItemKey);
+
+ // Act
+ const { result } = renderHook(() => useFiltersMapping(tabFrames));
+
+ // Assert
+ expect(result.current.selectedItemUpdater).toBeDefined();
+
+ // Act
+ result.current.selectedItemUpdater('title', 'accessorKey');
+
+ // Assert
+ expect(updateSelectedItemKey).toHaveBeenCalledWith(
+ 'frame1',
+ '{"filter":{"accessorKey":["title"]}}'
+ );
+
+ // Act
+ result.current.selectedItemUpdater('title');
+
+ // Assert
+ expect(updateSelectedItemKey).toHaveBeenCalledWith(
+ 'frame1',
+ '{"filter":{}}'
+ );
+ });
+});
diff --git a/packages/design-system/src/components/cookiesLanding/useFiltersMapping.tsx b/packages/design-system/src/components/cookiesLanding/useFiltersMapping.tsx
new file mode 100644
index 000000000..ff39fab44
--- /dev/null
+++ b/packages/design-system/src/components/cookiesLanding/useFiltersMapping.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import { useCallback, useMemo } from 'react';
+import { useSidebar } from '@ps-analysis-tool/design-system';
+import type { TabFrames } from '@ps-analysis-tool/common';
+
+/**
+ * Hook to expose the selectedItemUpdater function.
+ * This function is used to update the selected item key and set the query object.
+ * @param tabFrames Tab frames to get the first frame from.
+ * @returns Object containing the selectedItemUpdater function.
+ */
+const useFiltersMapping = (tabFrames: TabFrames) => {
+ const firstFrame = useMemo(
+ () => Object.keys(tabFrames || {})?.[0] || '',
+ [tabFrames]
+ );
+
+ const updateSelectedItemKey = useSidebar(
+ ({ actions }) => actions.updateSelectedItemKey
+ );
+
+ const selectedItemUpdater = useCallback(
+ (title: string, accessorKey?: string) => {
+ const queryObject = accessorKey
+ ? {
+ [accessorKey]: [title],
+ }
+ : {};
+
+ const modifiedQuery = {
+ filter: {
+ ...queryObject,
+ },
+ };
+
+ updateSelectedItemKey(firstFrame, JSON.stringify(modifiedQuery));
+ },
+ [firstFrame, updateSelectedItemKey]
+ );
+
+ return { selectedItemUpdater };
+};
+
+export default useFiltersMapping;
diff --git a/packages/design-system/src/components/errorFallback/extensionReloadNotification.tsx b/packages/design-system/src/components/errorFallback/extensionReloadNotification.tsx
index fce416c01..d5bcf19d9 100644
--- a/packages/design-system/src/components/errorFallback/extensionReloadNotification.tsx
+++ b/packages/design-system/src/components/errorFallback/extensionReloadNotification.tsx
@@ -22,15 +22,33 @@ import React from 'react';
* Internal dependencies.
*/
import Button from '../button';
+interface ExtensionReloadNotificationProps {
+ tabId?: number;
+}
-const ExtensionReloadNotification = () => {
+const ExtensionReloadNotification = ({
+ tabId,
+}: ExtensionReloadNotificationProps) => {
return (
Looks like extension has been updated since devtool was open.
- window.location.reload()} text="Refresh panel" />
+ {
+ window.location.reload();
+ if (localStorage.getItem('psatOpenedAfterPageLoad') && tabId) {
+ try {
+ chrome.tabs.reload(tabId);
+ localStorage.removeItem('psatOpenedAfterPageLoad');
+ } catch (error) {
+ //Fail silenlty
+ }
+ }
+ }}
+ text="Refresh panel"
+ />
);
diff --git a/packages/design-system/src/components/index.ts b/packages/design-system/src/components/index.ts
index 9c089bdae..55209a6e1 100644
--- a/packages/design-system/src/components/index.ts
+++ b/packages/design-system/src/components/index.ts
@@ -27,6 +27,8 @@ export { default as Matrix } from './matrix';
export { default as MatrixComponentHorizontal } from './matrix/matrixComponent/matrixComponentHorizontal';
export type { MatrixComponentProps } from './matrix/matrixComponent';
export { default as CookiesLanding } from './cookiesLanding';
+export * from './cookiesLanding';
+export type { DataMapping } from './cookiesLanding/landingHeader';
export { default as CookiesMatrix } from './cookiesLanding/cookiesMatrix';
export { default as CookieDetails } from './cookieDetails';
export { default as Details } from './cookieDetails/details';
@@ -42,6 +44,10 @@ export * from './sidebar';
export { default as InspectButton } from './inspectButton';
export { default as ToastMessage } from './toastMessage';
export {
- default as CookiesLandingContainer,
- type CookiesLandingContainerProps,
-} from './cookiesLanding/cookieLandingHeaderContainer';
+ default as CookiesLandingWrapper,
+ type CookiesLandingWrapperProps,
+} from './cookiesLanding/cookiesLandingWrapper';
+export { default as MatrixContainer } from './matrixContainer';
+export { default as MenuBar } from './menuBar';
+export * from './menuBar';
+export { default as useFiltersMapping } from './cookiesLanding/useFiltersMapping';
diff --git a/packages/design-system/src/components/landingPage/index.tsx b/packages/design-system/src/components/landingPage/index.tsx
index 093f6be79..96c593431 100644
--- a/packages/design-system/src/components/landingPage/index.tsx
+++ b/packages/design-system/src/components/landingPage/index.tsx
@@ -99,7 +99,7 @@ const LandingPage = ({
/>
)}
{psInfoKey &&
}
-
{contentPanel}
+ {contentPanel &&
{contentPanel}
}
{children && (
diff --git a/packages/design-system/src/components/matrix/index.tsx b/packages/design-system/src/components/matrix/index.tsx
index 11ba3974f..356d11f9f 100644
--- a/packages/design-system/src/components/matrix/index.tsx
+++ b/packages/design-system/src/components/matrix/index.tsx
@@ -17,6 +17,7 @@
* External dependencies.
*/
import React from 'react';
+import classnames from 'classnames';
/**
* Internal dependencies.
@@ -25,9 +26,10 @@ import MatrixComponent, { type MatrixComponentProps } from './matrixComponent';
interface MatrixProps {
dataComponents: MatrixComponentProps[];
+ expand?: boolean;
}
-const Matrix = ({ dataComponents }: MatrixProps) => {
+const Matrix = ({ dataComponents, expand }: MatrixProps) => {
if (!dataComponents || !dataComponents.length) {
return null;
}
@@ -40,16 +42,32 @@ const Matrix = ({ dataComponents }: MatrixProps) => {
index === dataComponents.length - 1 ||
index === dataComponents.length - 2;
return (
-
+ className={classnames(
+ 'py-1 border-bright-gray dark:border-quartz',
+ {
+ 'border-b': !isLastTwoItems,
+ }
+ )}
+ >
+
dataComponent.onClick?.(dataComponent.title)}
+ className={classnames('p-3.5 w-full box-border', {
+ 'hover:opacity-90 active:opacity-50 hover:scale-[0.98] hover:bg-[#f5f5f5] hover:dark:bg-[#1d1d1d] hover:shadow-[inset_0_0_10px_5px_rgba(238,238,238,0.5)] hover:dark:shadow-[inset_0_0_10px_5px_rgba(32,32,32,0.1)] rounded-md transition-all duration-75 ease-in-out cursor-pointer':
+ dataComponent.onClick,
+ 'cursor-default': !dataComponent.onClick,
+ })}
+ >
+
+
+
);
}
return null;
diff --git a/packages/design-system/src/components/matrix/matrixComponent/index.tsx b/packages/design-system/src/components/matrix/matrixComponent/index.tsx
index 8fb3c38cc..bd93af98b 100644
--- a/packages/design-system/src/components/matrix/matrixComponent/index.tsx
+++ b/packages/design-system/src/components/matrix/matrixComponent/index.tsx
@@ -17,6 +17,7 @@
* External dependencies.
*/
import React from 'react';
+import classnames from 'classnames';
/**
* Internal dependencies.
@@ -27,10 +28,10 @@ export interface MatrixComponentProps {
color: string;
title: string;
description?: string;
+ onClick?: (title: string) => void;
count: number;
isExpanded?: boolean;
countClassName: string;
- containerClasses: string;
}
const MatrixComponent = ({
@@ -40,17 +41,16 @@ const MatrixComponent = ({
count,
isExpanded = false,
countClassName,
- containerClasses,
}: MatrixComponentProps) => {
return (
-
+
-
+
{title}
-
+
{count}
{description && isExpanded && (
diff --git a/packages/design-system/src/components/matrix/tests/matrix.tsx b/packages/design-system/src/components/matrix/tests/matrix.tsx
index c9e257928..0e61147ce 100644
--- a/packages/design-system/src/components/matrix/tests/matrix.tsx
+++ b/packages/design-system/src/components/matrix/tests/matrix.tsx
@@ -32,28 +32,37 @@ describe('Matrix', () => {
expect(container.firstChild).toBeNull();
});
- it('renders MatrixComponent for each dataComponent', () => {
+ it('renders MatrixComponent for each dataComponent', async () => {
const mockDataComponents: MatrixComponentProps[] = [
{
color: 'red',
title: 'Test title',
count: 10,
- countClassName: '',
+ countClassName: 'some-class',
containerClasses: '',
+ description: 'Test description',
},
{
color: 'blue',
- title: 'Test title',
+ title: 'Test title1',
count: 10,
- countClassName: '',
+ countClassName: 'some-class-2',
containerClasses: '',
},
];
- render(
);
+ const { rerender } = render(
+
+ );
const matrixContainer = screen.getByTestId('matrix');
expect(matrixContainer).toBeInTheDocument();
+
+ expect(await screen.findByText('Test title')).toBeInTheDocument();
+
+ rerender(
);
+
+ expect(await screen.findByText('Test description')).toBeInTheDocument();
});
});
diff --git a/packages/design-system/src/components/matrixContainer/index.tsx b/packages/design-system/src/components/matrixContainer/index.tsx
new file mode 100644
index 000000000..088af620a
--- /dev/null
+++ b/packages/design-system/src/components/matrixContainer/index.tsx
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React, { useState } from 'react';
+import classname from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { ChevronDown, InfoIcon } from '../../icons';
+import Matrix from '../matrix';
+import MatrixComponentHorizontal, {
+ MatrixComponentHorizontalProps,
+} from '../matrix/matrixComponent/matrixComponentHorizontal';
+import { MatrixComponentProps } from '../matrix/matrixComponent';
+
+interface MatrixContainerProps {
+ matrixData?: MatrixComponentProps[];
+ horizontalMatrixData?: MatrixComponentHorizontalProps[];
+ title?: string;
+ description?: string;
+ showMatrix?: boolean;
+ count?: number | null;
+ allowExpand?: boolean;
+ highlightTitle?: boolean;
+ capitalizeTitle?: boolean;
+ infoIconTitle?: string;
+}
+
+const MatrixContainer = ({
+ matrixData = [],
+ horizontalMatrixData = [],
+ title = 'Categories',
+ description = '',
+ showMatrix = true,
+ count = null,
+ allowExpand = true,
+ highlightTitle = false,
+ capitalizeTitle = false,
+ infoIconTitle,
+}: MatrixContainerProps) => {
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ return (
+
+
+
+ {allowExpand && (
+
+ setIsExpanded((state) => !state)}
+ data-testid="expand-button"
+ title={isExpanded ? 'Collapse View' : 'Expand View'}
+ >
+
+
+
+ )}
+
+
+ {title}
+ {Boolean(infoIconTitle) && (
+
+
+
+ )}
+ {count !== null && : {Number(count) || 0} }
+
+
+ {description}
+
+
+
+ {showMatrix && (
+
+ )}
+
+ {Boolean(horizontalMatrixData.length) && (
+
+ {horizontalMatrixData.map((data, index) => (
+
+ ))}
+
+ )}
+
+ );
+};
+
+export default MatrixContainer;
diff --git a/packages/design-system/src/components/menuBar/index.tsx b/packages/design-system/src/components/menuBar/index.tsx
new file mode 100644
index 000000000..83d22ed3b
--- /dev/null
+++ b/packages/design-system/src/components/menuBar/index.tsx
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import React, { useEffect, useState } from 'react';
+import classnames from 'classnames';
+import { Export } from '@ps-analysis-tool/design-system';
+
+/**
+ * Internal dependencies.
+ */
+import { isInCenter } from './utils';
+
+export type MenuData = Array<{
+ name: string;
+ link: string;
+}>;
+
+interface MenuBarProps {
+ disableReportDownload?: boolean;
+ downloadReport?: () => void;
+ menuData: MenuData;
+ extraClasses?: string;
+ scrollContainerId: string;
+}
+
+const MenuBar = ({
+ disableReportDownload = true,
+ downloadReport,
+ menuData,
+ extraClasses,
+ scrollContainerId,
+}: MenuBarProps) => {
+ const [selectedItem, setSelectedItem] = useState
(menuData[0].link);
+ const [isListenerDisabled, setIsListenerDisabled] = useState(false);
+
+ useEffect(() => {
+ let timeout: NodeJS.Timeout;
+ const element = document.getElementById(selectedItem);
+ if (element) {
+ element.scrollIntoView?.({ behavior: 'smooth' });
+ timeout = setTimeout(() => {
+ setIsListenerDisabled(false);
+ }, 700);
+ }
+ return () => {
+ if (timeout) {
+ clearTimeout(timeout);
+ }
+ };
+ }, [selectedItem]);
+
+ useEffect(() => {
+ const scrollContainer = document.getElementById(scrollContainerId);
+ const firstItemLink = menuData[0].link;
+ const lastItemLink = menuData[menuData.length - 1].link;
+
+ const handleScroll = () => {
+ if (isListenerDisabled || !scrollContainer) {
+ return;
+ }
+
+ const distanceScrolled = scrollContainer.scrollTop;
+ const maxScrollDistance =
+ scrollContainer.scrollHeight - scrollContainer.clientHeight;
+
+ menuData.forEach(({ link: id }) => {
+ const section = document.getElementById(id);
+ setSelectedItem((prev) => {
+ if (scrollContainer?.scrollTop === 0) {
+ return firstItemLink;
+ } else if (section && isInCenter(section) && prev !== id) {
+ return id;
+ } else if (maxScrollDistance - distanceScrolled < 5) {
+ return lastItemLink;
+ }
+ return prev;
+ });
+ });
+ };
+
+ scrollContainer?.addEventListener('scroll', handleScroll);
+ return () => {
+ scrollContainer?.removeEventListener('scroll', handleScroll);
+ };
+ }, [menuData, isListenerDisabled, scrollContainerId]);
+
+ return (
+
+ {downloadReport && (
+
+
{
+ downloadReport();
+ }}
+ >
+
+ {disableReportDownload
+ ? 'Wait for library detection'
+ : 'Download Report'}
+
+
+
+
+
+
+ )}
+
+ {menuData.map((item, index) => (
+ {
+ setIsListenerDisabled(true);
+ setSelectedItem(item.link);
+ }}
+ >
+
+
+ ))}
+
+ );
+};
+
+export default MenuBar;
diff --git a/packages/design-system/src/components/menuBar/utils/index.ts b/packages/design-system/src/components/menuBar/utils/index.ts
new file mode 100644
index 000000000..0b96114b6
--- /dev/null
+++ b/packages/design-system/src/components/menuBar/utils/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { default as isInCenter } from './isInCenter';
diff --git a/packages/design-system/src/components/menuBar/utils/isInCenter.ts b/packages/design-system/src/components/menuBar/utils/isInCenter.ts
new file mode 100644
index 000000000..0481a779b
--- /dev/null
+++ b/packages/design-system/src/components/menuBar/utils/isInCenter.ts
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Determines if an HTMLElement is vertically centered within the viewport.
+ * @param {HTMLElement} element - The HTMLElement to check for vertical centering.
+ * @returns {boolean} True if the element is vertically centered within the viewport, false otherwise.
+ */
+const isInCenter = (element: HTMLElement) => {
+ const rect = element.getBoundingClientRect();
+ const viewportHeight =
+ window.innerHeight || document.documentElement.clientHeight;
+
+ const elementTop = rect.top;
+ const elementBottom = rect.bottom;
+ const elementHeight = elementBottom - elementTop;
+
+ const elementCenterY = elementTop + elementHeight / 2;
+ const viewportCenterY = viewportHeight / 2;
+
+ return Math.abs(elementCenterY - viewportCenterY) <= elementHeight / 2;
+};
+
+export default isInCenter;
diff --git a/packages/design-system/src/components/progressBar/index.tsx b/packages/design-system/src/components/progressBar/index.tsx
index 436898cfa..ef7d10992 100644
--- a/packages/design-system/src/components/progressBar/index.tsx
+++ b/packages/design-system/src/components/progressBar/index.tsx
@@ -24,6 +24,7 @@ interface ProgressBarProps {
const ProgressBar = ({ additionalStyles = '' }: ProgressBarProps) => {
return (
diff --git a/packages/design-system/src/components/sidebar/index.ts b/packages/design-system/src/components/sidebar/index.ts
index 8b6e8399e..3e45714bd 100644
--- a/packages/design-system/src/components/sidebar/index.ts
+++ b/packages/design-system/src/components/sidebar/index.ts
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-export { default as useSidebar } from './useSidebar';
export * from './useSidebar';
+export * from './useSidebar/constants';
export { default as Sidebar } from './sidebar';
diff --git a/packages/design-system/src/components/sidebar/sidebar.tsx b/packages/design-system/src/components/sidebar/sidebar.tsx
index ac59ce7df..6faa920fd 100644
--- a/packages/design-system/src/components/sidebar/sidebar.tsx
+++ b/packages/design-system/src/components/sidebar/sidebar.tsx
@@ -23,36 +23,20 @@ import React, { useEffect, useRef, useState } from 'react';
* Internal dependencies.
*/
import SidebarChild from './sidebarChild';
-import type { SidebarItems } from './useSidebar';
+import { useSidebar } from './useSidebar';
interface SidebarProps {
- selectedItemKey: string | null;
- sidebarItems: SidebarItems;
- isSidebarFocused: boolean;
- setIsSidebarFocused: React.Dispatch
;
- updateSelectedItemKey: (key: string | null) => void;
- onKeyNavigation: (
- event: React.KeyboardEvent,
- key: string | null
- ) => void;
- toggleDropdown: (action: boolean, key: string) => void;
- isKeyAncestor: (key: string) => boolean;
- isKeySelected: (key: string) => boolean;
visibleWidth?: number;
}
-const Sidebar = ({
- selectedItemKey,
- sidebarItems,
- isSidebarFocused,
- setIsSidebarFocused,
- updateSelectedItemKey,
- onKeyNavigation,
- toggleDropdown,
- isKeyAncestor,
- isKeySelected,
- visibleWidth,
-}: SidebarProps) => {
+const Sidebar = ({ visibleWidth }: SidebarProps) => {
+ const { sidebarItems, setIsSidebarFocused } = useSidebar(
+ ({ state, actions }) => ({
+ sidebarItems: state.sidebarItems,
+ setIsSidebarFocused: actions.setIsSidebarFocused,
+ })
+ );
+
const [didUserInteract, setDidUserInteract] = useState(false);
const sidebarContainerRef = useRef(null);
@@ -74,22 +58,17 @@ const Sidebar = ({
}, [setIsSidebarFocused]);
return (
-
+
{Object.entries(sidebarItems).map(([itemKey, sidebarItem]) => (
diff --git a/packages/design-system/src/components/sidebar/sidebarChild.tsx b/packages/design-system/src/components/sidebar/sidebarChild.tsx
index cf3e161af..243213228 100644
--- a/packages/design-system/src/components/sidebar/sidebarChild.tsx
+++ b/packages/design-system/src/components/sidebar/sidebarChild.tsx
@@ -21,49 +21,52 @@ import {
ArrowDown,
ArrowDownWhite,
InfoIcon,
+ SidebarItemValue,
+ useSidebar,
} from '@ps-analysis-tool/design-system';
/**
* Internal dependencies.
*/
-import type { SidebarItemValue } from './useSidebar';
interface SidebarItemProps {
- selectedItemKey: string | null;
didUserInteract: boolean;
setDidUserInteract: (didUserInteract: boolean) => void;
itemKey: string;
sidebarItem: SidebarItemValue;
- isSidebarFocused: boolean;
- setIsSidebarFocused: React.Dispatch
;
- updateSelectedItemKey: (key: string | null) => void;
- onKeyNavigation: (
- event: React.KeyboardEvent,
- key: string | null
- ) => void;
- toggleDropdown: (action: boolean, key: string) => void;
- isKeyAncestor: (key: string) => boolean;
- isKeySelected: (key: string) => boolean;
recursiveStackIndex?: number;
visibleWidth?: number;
}
+// eslint-disable-next-line complexity
const SidebarChild = ({
- selectedItemKey,
didUserInteract,
setDidUserInteract,
itemKey,
sidebarItem,
- isSidebarFocused,
- setIsSidebarFocused,
- updateSelectedItemKey,
- onKeyNavigation,
- toggleDropdown,
- isKeyAncestor,
- isKeySelected,
recursiveStackIndex = 0,
visibleWidth,
}: SidebarItemProps) => {
+ const {
+ selectedItemKey,
+ isSidebarFocused,
+ setIsSidebarFocused,
+ updateSelectedItemKey,
+ toggleDropdown,
+ isKeyAncestor,
+ isKeySelected,
+ onKeyNavigation,
+ } = useSidebar(({ state, actions }) => ({
+ selectedItemKey: state.selectedItemKey,
+ isSidebarFocused: state.isSidebarFocused,
+ setIsSidebarFocused: actions.setIsSidebarFocused,
+ updateSelectedItemKey: actions.updateSelectedItemKey,
+ toggleDropdown: actions.toggleDropdown,
+ isKeyAncestor: actions.isKeyAncestor,
+ isKeySelected: actions.isKeySelected,
+ onKeyNavigation: actions.onKeyNavigation,
+ }));
+
const itemRef = useRef(null);
useEffect(() => {
@@ -78,6 +81,10 @@ const SidebarChild = ({
setIsSidebarFocused,
]);
+ const SelectedIcon = sidebarItem.selectedIcon?.Element;
+ const Icon = sidebarItem.icon?.Element;
+ const ExtraInterfaceToTitle = sidebarItem.extraInterfaceToTitle?.Element;
+
return (
<>
{/* SidebarItem */}
@@ -102,6 +109,7 @@ const SidebarChild = ({
: 'bg-white dark:bg-raisin-black'
} cursor-pointer ${sidebarItem.isBlurred ? 'opacity-50' : ''}`}
style={{ paddingLeft: recursiveStackIndex * 16 + 12 }}
+ data-testid="sidebar-child"
>
{Object.keys(sidebarItem.children)?.length !== 0 && (
{isKeyAncestor(itemKey) ||
@@ -125,11 +134,11 @@ const SidebarChild = ({
)}
{sidebarItem.icon && sidebarItem.selectedIcon && (
- {isKeySelected(itemKey) && isSidebarFocused ? (
- <>{sidebarItem.selectedIcon}>
- ) : (
- <>{sidebarItem.icon}>
- )}
+ {isKeySelected(itemKey) && isSidebarFocused
+ ? SelectedIcon && (
+
+ )
+ : Icon && }
)}
@@ -152,9 +161,14 @@ const SidebarChild = ({
left: visibleWidth ? visibleWidth - 35 : 0,
}}
>
- {sidebarItem.extraInterfaceToTitle}
+ {ExtraInterfaceToTitle && (
+
+ )}
+ {/* Sidebar item's children */}
<>
{Object.keys(sidebarItem.children)?.length !== 0 &&
sidebarItem.dropdownOpen && (
@@ -162,18 +176,10 @@ const SidebarChild = ({
{Object.entries(sidebarItem.children).map(([childKey, child]) => (
diff --git a/packages/design-system/src/components/sidebar/tests/sidebar.tsx b/packages/design-system/src/components/sidebar/tests/sidebar.tsx
new file mode 100644
index 000000000..9504b23c1
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/tests/sidebar.tsx
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import { fireEvent, render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import Sidebar from '../sidebar';
+import { useSidebar } from '../useSidebar';
+
+jest.mock('../useSidebar', () => ({
+ useSidebar: jest.fn(),
+}));
+const mockUseSidebar = useSidebar as jest.Mock;
+const initialState = {
+ sidebarItems: {
+ item1: {
+ title: 'item1',
+ children: {
+ item2: {
+ title: 'item2',
+ children: {},
+ },
+ },
+ },
+ },
+ setIsSidebarFocused: jest.fn(),
+ selectedItemKey: '',
+ isSidebarFocused: false,
+ setISidebarFocused: jest.fn(),
+ updateSelectedItemKey: jest.fn(),
+ toggleDropdown: jest.fn(),
+ isKeyAncestor: jest.fn(),
+ isKeySelected: jest.fn(),
+ onKeyNavigation: jest.fn(),
+};
+
+describe('Sidebar', () => {
+ beforeEach(() => {
+ mockUseSidebar.mockReturnValue(initialState);
+ });
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should render correctly', async () => {
+ // Arrange
+ const props = {
+ visibleWidth: 200,
+ };
+
+ // Act
+ render( );
+
+ // Assert
+ const sidebar = await screen.findByTestId('sidebar');
+ expect(sidebar).toBeInTheDocument();
+ });
+
+ it('should call setIsSidebarFocused when clicking outside the sidebar', async () => {
+ // Arrange
+ const props = {
+ visibleWidth: 200,
+ };
+
+ // Act
+ render( );
+
+ // Assert
+ expect(initialState.setIsSidebarFocused).not.toHaveBeenCalled();
+
+ // Act
+ document.dispatchEvent(new MouseEvent('click'));
+
+ // Assert
+ expect(initialState.setIsSidebarFocused).toHaveBeenCalled();
+ expect(initialState.setIsSidebarFocused).toHaveBeenCalledWith(false);
+
+ const sidebar = await screen.findByTestId('sidebar-child');
+ expect(sidebar).toBeInTheDocument();
+
+ // Act
+ fireEvent.click(sidebar);
+
+ // Assert
+ expect(initialState.setIsSidebarFocused).toHaveBeenCalledWith(true);
+ });
+
+ it('should handle callbacks', async () => {
+ // Arrange
+ const props = {
+ visibleWidth: 200,
+ };
+
+ // Act
+ render( );
+
+ // Assert
+ expect(initialState.updateSelectedItemKey).not.toHaveBeenCalled();
+
+ const sidebar = await screen.findByTestId('sidebar-child');
+ expect(sidebar).toBeInTheDocument();
+
+ // Act
+ fireEvent.click(sidebar);
+
+ // Assert
+ expect(initialState.updateSelectedItemKey).toHaveBeenCalled();
+ expect(initialState.updateSelectedItemKey).toHaveBeenCalledWith('item1');
+
+ // Act
+ const dropdown = await screen.findByTestId('sidebar-child-dropdown');
+ fireEvent.click(dropdown);
+
+ // Assert
+ expect(initialState.toggleDropdown).toHaveBeenCalled();
+ expect(initialState.toggleDropdown).toHaveBeenCalledWith(true, 'item1');
+
+ // Act
+ fireEvent.keyDown(sidebar, { key: 'ArrowDown' });
+
+ // Assert
+ expect(initialState.onKeyNavigation).toHaveBeenCalled();
+ expect(initialState.onKeyNavigation).toHaveBeenCalledWith(
+ expect.any(Object),
+ 'item1'
+ );
+ });
+});
diff --git a/packages/design-system/src/components/sidebar/useSidebar/constants.ts b/packages/design-system/src/components/sidebar/useSidebar/constants.ts
new file mode 100644
index 000000000..b86fb4cb1
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/constants.ts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export enum SIDEBAR_ITEMS_KEYS {
+ COOKIES = 'cookies',
+ COOKIES_WITH_ISSUES = 'cookie-issues',
+ TECHNOLOGIES = 'technologies',
+ PRIVACY_SANDBOX = 'privacy-sandbox',
+ SITE_BOUNDARIES = 'site-boundaries',
+ CHIPS = 'chips',
+ RELATED_WEBSITE_SETS = 'related-website-sets',
+ PRIVATE_ADVERTISING = 'private-advertising',
+ TOPICS = 'topics',
+ ATTRIBUTION = 'attribution',
+ ANTI_COVERT_TRACKING = 'anti-covert-tracking',
+ BOUNCE_TRACKING = 'bounce-tracking',
+ FINGERPRINTING = 'fingerprinting',
+ FACILITATED_TESTING = 'facilitated-testing',
+ SETTINGS = 'settings',
+}
diff --git a/packages/design-system/src/components/sidebar/useSidebar/context.ts b/packages/design-system/src/components/sidebar/useSidebar/context.ts
new file mode 100644
index 000000000..46d190b3a
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/context.ts
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import { createContext, noop } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import { SidebarComponent, SidebarItems } from './types';
+
+export interface SidebarStoreContext {
+ state: {
+ activePanel: {
+ panel: SidebarComponent;
+ query?: string;
+ clearQuery?: () => void;
+ };
+ selectedItemKey: string | null; //Entire chained item key eg Privacy-Sandbox#cookies#frameUrl
+ currentItemKey: string | null; //Last sidebar item key in selectedItemKey eg frameUrl
+ sidebarItems: SidebarItems;
+ isSidebarFocused: boolean;
+ };
+ actions: {
+ setIsSidebarFocused: React.Dispatch;
+ updateSelectedItemKey: (key: string | null, queryString?: string) => void;
+ onKeyNavigation: (
+ event: React.KeyboardEvent,
+ key: string | null
+ ) => void;
+ toggleDropdown: (action: boolean, key: string) => void;
+ isKeyAncestor: (key: string) => boolean;
+ isKeySelected: (key: string) => boolean;
+ };
+}
+
+export const initialState: SidebarStoreContext = {
+ state: {
+ activePanel: {
+ panel: {
+ Element: () => '' as any,
+ props: {},
+ },
+ query: '',
+ clearQuery: noop,
+ },
+ selectedItemKey: null,
+ currentItemKey: null,
+ sidebarItems: {},
+ isSidebarFocused: true,
+ },
+ actions: {
+ setIsSidebarFocused: noop,
+ updateSelectedItemKey: noop,
+ onKeyNavigation: noop,
+ toggleDropdown: noop,
+ isKeyAncestor: () => false,
+ isKeySelected: () => false,
+ },
+};
+
+export const SidebarContext = createContext(initialState);
diff --git a/packages/design-system/src/components/sidebar/useSidebar/index.ts b/packages/design-system/src/components/sidebar/useSidebar/index.ts
new file mode 100644
index 000000000..c2e8430f9
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export * from './provider';
+export * from './types';
+export * from './useSidebar';
diff --git a/packages/design-system/src/components/sidebar/useSidebar/index.tsx b/packages/design-system/src/components/sidebar/useSidebar/provider.tsx
similarity index 59%
rename from packages/design-system/src/components/sidebar/useSidebar/index.tsx
rename to packages/design-system/src/components/sidebar/useSidebar/provider.tsx
index 6eece3214..5061296b8 100644
--- a/packages/design-system/src/components/sidebar/useSidebar/index.tsx
+++ b/packages/design-system/src/components/sidebar/useSidebar/provider.tsx
@@ -16,7 +16,13 @@
/**
* External dependencies.
*/
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import React, {
+ PropsWithChildren,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from 'react';
/**
* Internal dependencies.
@@ -28,59 +34,34 @@ import {
findPrevItem,
matchKey,
} from './utils';
+import { SidebarItems, useSidebarProps } from './types';
+import { SidebarContext, SidebarStoreContext, initialState } from './context';
-export type SidebarItemValue = {
- title: string;
- children: SidebarItems;
- popupTitle?: string;
- infoIconDescription?: string;
- extraInterfaceToTitle?: React.ReactNode;
- dropdownOpen?: boolean;
- panel?: React.ReactNode;
- icon?: React.ReactNode;
- selectedIcon?: React.ReactNode;
- isBlurred?: boolean;
-};
-
-export type SidebarItems = {
- [key: string]: SidebarItemValue;
-};
-
-export interface SidebarOutput {
- activePanel: React.ReactNode;
- selectedItemKey: string | null; //Entire chained item key eg Privacy-Sandbox#cookies#frameUrl
- currentItemKey: string | null; //Last sidebar item key in selectedItemKey eg frameUrl
- sidebarItems: SidebarItems;
- isSidebarFocused: boolean;
- setIsSidebarFocused: React.Dispatch;
- updateSelectedItemKey: (key: string | null) => void;
- onKeyNavigation: (
- event: React.KeyboardEvent,
- key: string | null
- ) => void;
- toggleDropdown: (action: boolean, key: string) => void;
- isKeyAncestor: (key: string) => boolean;
- isKeySelected: (key: string) => boolean;
-}
-
-interface useSidebarProps {
- data: SidebarItems;
- defaultSelectedItemKey?: string | null;
-}
-
-const useSidebar = ({
+export const SidebarProvider = ({
data,
defaultSelectedItemKey = null,
-}: useSidebarProps): SidebarOutput => {
+ children,
+}: PropsWithChildren) => {
const [selectedItemKey, setSelectedItemKey] = useState(null);
- const [activePanel, setActivePanel] = useState(); // TODO: Should we use React.ReactNode in state?
+ const [activePanel, setActivePanel] = useState<
+ SidebarStoreContext['state']['activePanel']
+ >(initialState.state.activePanel);
+ const [query, setQuery] = useState('');
const [sidebarItems, setSidebarItems] = useState({});
const [isSidebarFocused, setIsSidebarFocused] = useState(true);
+ /**
+ * Update the selected item key when the defaultSelectedItemKey loads.
+ */
useEffect(() => {
setSelectedItemKey(defaultSelectedItemKey);
}, [defaultSelectedItemKey]);
+ /**
+ * Get the last sidebar item key in selectedItemKey chain.
+ * Eg: selectedItemKey = 'Privacy-Sandbox#cookies#frameUrl'
+ * currentItemKey = 'frameUrl'
+ */
const currentItemKey = useMemo(() => {
if (!selectedItemKey) {
return null;
@@ -92,13 +73,25 @@ const useSidebar = ({
return keys[length - 1];
}, [selectedItemKey]);
+ /**
+ * Update the sidebar items when the sidebar data changes.
+ */
useEffect(() => {
setSidebarItems(data);
}, [data]);
+ /**
+ * Find the active panel when the selected item key changes.
+ */
useEffect(() => {
let keyFound = false;
+ /**
+ * Find the active panel, if the selected item key is matched with the item key.
+ * If the item key is matched, set the active panel.
+ * If the item has children, recursively find the active panel.
+ * @param items Sidebar items.
+ */
const findActivePanel = (items: SidebarItems) => {
Object.entries(items).forEach(([itemKey, item]) => {
if (keyFound) {
@@ -106,7 +99,15 @@ const useSidebar = ({
}
if (matchKey(selectedItemKey || '', itemKey)) {
- setActivePanel(item.panel);
+ if (item.panel) {
+ setActivePanel({
+ query,
+ clearQuery: () => {
+ setTimeout(() => setQuery(''));
+ },
+ panel: item.panel,
+ });
+ }
keyFound = true;
return;
@@ -121,10 +122,15 @@ const useSidebar = ({
if (selectedItemKey) {
findActivePanel(sidebarItems);
}
- }, [selectedItemKey, sidebarItems]);
+ }, [query, selectedItemKey, sidebarItems]);
+ /**
+ * Update the selected item key and query string.
+ * @param key Selected item key.
+ * @param queryString Query string to pass to the new panel.
+ */
const updateSelectedItemKey = useCallback(
- (key: string | null) => {
+ (key: string | null, queryString = '') => {
const keyPath = createKeyPath(sidebarItems, key || '');
if (!keyPath.length) {
@@ -133,10 +139,16 @@ const useSidebar = ({
}
setSelectedItemKey(keyPath.join('#'));
+ setQuery(queryString);
},
[sidebarItems]
);
+ /**
+ * Toggle the dropdown of the sidebar item.
+ * @param action Dropdown action.
+ * @param key Sidebar item key to toggle dropdown.
+ */
const toggleDropdown = useCallback((action: boolean, key: string) => {
setSidebarItems((prev) => {
const items = { ...prev };
@@ -150,6 +162,11 @@ const useSidebar = ({
});
}, []);
+ /**
+ * Handle keyboard navigation in the sidebar.
+ * @param event Keyboard event.
+ * @param key Sidebar item key to navigate.
+ */
const onKeyNavigation = useCallback(
(event: React.KeyboardEvent, key: string | null) => {
event.preventDefault();
@@ -166,12 +183,18 @@ const useSidebar = ({
return;
}
+ /**
+ * Open or close the dropdown based on the navigation action.
+ */
if (navigationAction === 'ArrowRight') {
toggleDropdown(true, key);
} else if (navigationAction === 'ArrowLeft') {
toggleDropdown(false, key);
}
+ /**
+ * Navigate to the previous or next sidebar item based on the navigation action.
+ */
if (navigationAction === 'ArrowUp') {
const prevItem = findPrevItem(sidebarItems, keyPath);
@@ -195,6 +218,11 @@ const useSidebar = ({
[sidebarItems, toggleDropdown, updateSelectedItemKey]
);
+ /**
+ * Check if the key is an ancestor of the selected item key.
+ * @param key Sidebar item key to check.
+ * @returns boolean
+ */
const isKeyAncestor = useCallback(
(key: string) => {
if (!selectedItemKey) {
@@ -209,6 +237,13 @@ const useSidebar = ({
[selectedItemKey]
);
+ /**
+ * Check if the key is present in the selected item key chain.
+ * Eg: selectedItemKey = 'Privacy-Sandbox#cookies#frameUrl'
+ * isKeySelected('frameUrl') => true
+ * @param key Sidebar item key to check.
+ * @returns boolean
+ */
const isKeySelected = useCallback(
(key: string) => {
if (!selectedItemKey) {
@@ -223,19 +258,27 @@ const useSidebar = ({
[selectedItemKey]
);
- return {
- activePanel,
- selectedItemKey,
- currentItemKey,
- sidebarItems,
- isSidebarFocused,
- setIsSidebarFocused,
- updateSelectedItemKey,
- onKeyNavigation,
- toggleDropdown,
- isKeyAncestor,
- isKeySelected,
- };
+ return (
+
+ {children}
+
+ );
};
-
-export default useSidebar;
diff --git a/packages/design-system/src/components/sidebar/useSidebar/types.ts b/packages/design-system/src/components/sidebar/useSidebar/types.ts
new file mode 100644
index 000000000..3d0a1ab4d
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/types.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export type SidebarComponent = {
+ Element?: (props: any) => React.JSX.Element;
+ props?: Record;
+};
+
+export type SidebarItemValue = {
+ title: string;
+ children: SidebarItems;
+ popupTitle?: string;
+ infoIconDescription?: string;
+ extraInterfaceToTitle?: SidebarComponent;
+ dropdownOpen?: boolean;
+ panel?: SidebarComponent;
+ icon?: SidebarComponent;
+ selectedIcon?: SidebarComponent;
+ isBlurred?: boolean;
+};
+
+export type SidebarItems = {
+ [key: string]: SidebarItemValue;
+};
+
+export interface useSidebarProps {
+ data: SidebarItems;
+ defaultSelectedItemKey?: string | null;
+}
diff --git a/packages/design-system/src/components/sidebar/useSidebar/useSidebar.tsx b/packages/design-system/src/components/sidebar/useSidebar/useSidebar.tsx
new file mode 100644
index 000000000..7602c7538
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/useSidebar.tsx
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { useContextSelector } from '@ps-analysis-tool/common';
+import { SidebarContext, SidebarStoreContext } from './context';
+
+export function useSidebar(): SidebarStoreContext;
+export function useSidebar(selector: (state: SidebarStoreContext) => T): T;
+
+/**
+ * Hook to access the Sidebar context.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useSidebar(
+ selector: (state: SidebarStoreContext) => T | SidebarStoreContext = (state) =>
+ state
+) {
+ return useContextSelector(SidebarContext, selector);
+}
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/createKeyPath.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/createKeyPath.ts
index 956aaaa14..461ea8346 100644
--- a/packages/design-system/src/components/sidebar/useSidebar/utils/createKeyPath.ts
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/createKeyPath.ts
@@ -17,9 +17,16 @@
/**
* Internal dependencies
*/
-import { SidebarItems } from '..';
+import { SidebarItems } from '../types';
import matchKey from './matchKey';
+/**
+ * Create a key path to the given key in the sidebar items.
+ * @param items Sidebar items.
+ * @param key Key up to which the path should be created.
+ * @param keyPath Prefix key path to start with.
+ * @returns Key path.
+ */
const createKeyPath = (
items: SidebarItems,
key: string,
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/findItem.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/findItem.ts
index e5bfd6b24..b5f32bcb1 100644
--- a/packages/design-system/src/components/sidebar/useSidebar/utils/findItem.ts
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/findItem.ts
@@ -17,9 +17,17 @@
/**
* Internal dependencies
*/
-import { SidebarItemValue, SidebarItems } from '..';
+import { SidebarItemValue, SidebarItems } from '../types';
import matchKey from './matchKey';
+/**
+ * Find an item in the sidebar items by key.
+ * The SidebarItems are assumed to be a tree structure.
+ * Tree traversal is done in a depth-first manner to find the item.
+ * @param items Sidebar items.
+ * @param key Key to find.
+ * @returns Sidebar item.
+ */
const findItem = (
items: SidebarItems,
key: string | null
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/findKeyParent.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/findKeyParent.ts
index 8f36bce54..93b71dd4d 100644
--- a/packages/design-system/src/components/sidebar/useSidebar/utils/findKeyParent.ts
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/findKeyParent.ts
@@ -14,6 +14,12 @@
* limitations under the License.
*/
+/**
+ * Find the parent key of the given key path.
+ * Eg if the key path is ['a', 'b', 'c'], the parent key is 'b'.
+ * @param keyPath Key path array.
+ * @returns Parent key.
+ */
const findKeyParent = (keyPath: string[]) => {
const length = keyPath.length;
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/findNextItem.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/findNextItem.ts
index 4c4df6748..808e72e4b 100644
--- a/packages/design-system/src/components/sidebar/useSidebar/utils/findNextItem.ts
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/findNextItem.ts
@@ -17,16 +17,32 @@
/**
* Internal dependencies
*/
-import { SidebarItemValue, SidebarItems } from '..';
+import { SidebarItemValue, SidebarItems } from '../types';
import findItem from './findItem';
import findKeyParent from './findKeyParent';
+/**
+ * Handle the next item on the parent from the children.
+ * @param currentItem Current item.
+ * @returns Next item key.
+ */
const handleNextItemOnParent = (currentItem: SidebarItemValue) => {
const children = Object.keys(currentItem.children);
return children.length ? children[0] : null;
};
+/**
+ * Find the next item in the sidebar based on the key path.
+ * The SidebarItems are assumed to be a tree structure.
+ * The key path is an array of keys that represent the path to the current item.
+ * Tree traversal is done in a depth-first manner to find the parent of the current item.
+ * And then the next sibling of the current item.
+ * @param items Sidebar items.
+ * @param keyPath Key path.
+ * @param skipDropdown Skip dropdown if parent has only one child, so find parent's sibling.
+ * @returns Next item key.
+ */
const findNextItem = (
items: SidebarItems,
keyPath: string[],
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/findPrevItem.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/findPrevItem.ts
index 4f0e01d49..7b6435a19 100644
--- a/packages/design-system/src/components/sidebar/useSidebar/utils/findPrevItem.ts
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/findPrevItem.ts
@@ -17,10 +17,20 @@
/**
* Internal dependencies
*/
-import { SidebarItems } from '..';
+import { SidebarItems } from '../types';
import findItem from './findItem';
import findKeyParent from './findKeyParent';
+/**
+ * Find the previous item in the sidebar based on the key path.
+ * The SidebarItems are assumed to be a tree structure.
+ * The key path is an array of keys that represent the path to the current item.
+ * Tree traversal is done in a depth-first manner to find the parent of the current item.
+ * And then the previous sibling of the current item.
+ * @param items Sidebar items.
+ * @param keyPath Key path.
+ * @returns Previous item key.
+ */
const findPrevItem = (items: SidebarItems, keyPath: string[]) => {
if (keyPath.length === 0) {
return null;
@@ -41,12 +51,13 @@ const findPrevItem = (items: SidebarItems, keyPath: string[]) => {
return parentKey;
}
- const prevKey = keys[currentIndex - 1];
- const prevItem = children[prevKey];
+ let prevKey = keys[currentIndex - 1];
+ let prevItem = children[prevKey];
- if (prevItem?.dropdownOpen) {
+ while (prevItem?.dropdownOpen) {
const prevItemChildren = Object.keys(prevItem.children);
- return prevItemChildren[prevItemChildren.length - 1];
+ prevItem = prevItem.children[prevItemChildren[prevItemChildren.length - 1]];
+ prevKey = prevItemChildren[prevItemChildren.length - 1];
}
return prevKey;
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/matchKey.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/matchKey.ts
index 53453a43f..582b50cb0 100644
--- a/packages/design-system/src/components/sidebar/useSidebar/utils/matchKey.ts
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/matchKey.ts
@@ -14,8 +14,12 @@
* limitations under the License.
*/
-/** */
-
+/**
+ * Match toMatch key with the last key in the chained key.
+ * @param key chained key to match with.
+ * @param toMatch String to match.
+ * @returns Boolean.
+ */
const matchKey = (key: string, toMatch: string) => {
const keys = key.split('#');
const length = keys.length;
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/tests/createKeyPath.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/createKeyPath.ts
new file mode 100644
index 000000000..8e6a09212
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/createKeyPath.ts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import createKeyPath from '../createKeyPath';
+
+describe('createKeyPath', () => {
+ it('should create a key path', () => {
+ const items = {
+ item1: {
+ title: 'Item 1',
+ children: {
+ item2: {
+ title: 'Item 2',
+ children: {
+ item3: {
+ title: 'Item 3',
+ children: {
+ item4: {
+ title: 'Item 4',
+ children: {},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ let key = 'item4';
+
+ const result = createKeyPath(items, key);
+
+ expect(result).toEqual(['item1', 'item2', 'item3', 'item4']);
+
+ key = 'item5';
+
+ const result2 = createKeyPath(items, key);
+
+ expect(result2).toEqual([]);
+ });
+});
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findItem.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findItem.ts
new file mode 100644
index 000000000..99c19024e
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findItem.ts
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import findItem from '../findItem';
+
+describe('findItem', () => {
+ it('should find an item', () => {
+ const items = {
+ item1: {
+ title: 'Item 1',
+ children: {
+ item2: {
+ title: 'Item 2',
+ children: {
+ item3: {
+ title: 'Item 3',
+ children: {
+ item4: {
+ title: 'Item 4',
+ children: {},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ let key = 'item4';
+
+ const result = findItem(items, key);
+
+ expect(result).toEqual({ title: 'Item 4', children: {} });
+
+ key = 'item5';
+
+ const result2 = findItem(items, key);
+
+ expect(result2).toEqual(null);
+ });
+});
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findKeyParent.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findKeyParent.ts
new file mode 100644
index 000000000..0dbb84207
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findKeyParent.ts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import findKeyParent from '../findKeyParent';
+
+describe('findKeyPareny', () => {
+ it('should find the parent key', () => {
+ const keyPath = ['item1', 'item2', 'item3', 'item4'];
+
+ const result = findKeyParent(keyPath);
+
+ expect(result).toEqual('item3');
+ });
+
+ it('should return null if there is no parent', () => {
+ const keyPath = ['item1'];
+
+ const result = findKeyParent(keyPath);
+
+ expect(result).toEqual(null);
+ });
+});
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findNextItem.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findNextItem.ts
new file mode 100644
index 000000000..581e84657
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findNextItem.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { SidebarItems } from '../../types';
+import findNextItem from '../findNextItem';
+
+describe('findNextItem', () => {
+ it('should find the next item', () => {
+ const items: SidebarItems = {
+ item1: {
+ title: 'Item 1',
+ children: {
+ item2: {
+ title: 'Item 2',
+ children: {
+ item3: {
+ title: 'Item 3',
+ dropdownOpen: true,
+ children: {
+ item4: {
+ title: 'Item 4',
+ children: {},
+ },
+ item6: {
+ title: 'Item 6',
+ children: {},
+ },
+ },
+ },
+ },
+ },
+ item5: {
+ title: 'Item 5',
+ children: {},
+ },
+ },
+ },
+ };
+
+ const keyPath = ['item1', 'item2', 'item3', 'item4'];
+
+ const result = findNextItem(items, keyPath);
+
+ expect(result).toEqual('item6');
+
+ const keyPath2 = ['item1', 'item2', 'item3', 'item6'];
+
+ const result2 = findNextItem(items, keyPath2);
+
+ expect(result2).toEqual('item5');
+ });
+});
diff --git a/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findPrevItem.ts b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findPrevItem.ts
new file mode 100644
index 000000000..fbb2bf3c1
--- /dev/null
+++ b/packages/design-system/src/components/sidebar/useSidebar/utils/tests/findPrevItem.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { SidebarItems } from '../../types';
+import findPrevItem from '../findPrevItem';
+
+describe('findPrevItem', () => {
+ it('should find the previous item', () => {
+ const items: SidebarItems = {
+ item1: {
+ title: 'Item 1',
+ children: {
+ item2: {
+ title: 'Item 2',
+ dropdownOpen: true,
+ children: {
+ item3: {
+ title: 'Item 3',
+ dropdownOpen: true,
+ children: {
+ item4: {
+ title: 'Item 4',
+ children: {},
+ },
+ item6: {
+ title: 'Item 6',
+ children: {
+ item7: {
+ title: 'Item 7',
+ children: {},
+ },
+ item8: {
+ title: 'Item 8',
+ children: {},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ item5: {
+ title: 'Item 5',
+ children: {},
+ },
+ },
+ },
+ };
+
+ const keyPath = ['item1', 'item2', 'item3', 'item4'];
+
+ const result = findPrevItem(items, keyPath);
+
+ expect(result).toEqual('item3');
+
+ const keyPath2 = ['item1', 'item5'];
+
+ const result2 = findPrevItem(items, keyPath2);
+
+ expect(result2).toEqual('item6');
+ });
+});
diff --git a/packages/design-system/src/components/table/components/columnMenu/columnList.tsx b/packages/design-system/src/components/table/components/columnMenu/columnList.tsx
index 6bda1dc3c..111e55fce 100644
--- a/packages/design-system/src/components/table/components/columnMenu/columnList.tsx
+++ b/packages/design-system/src/components/table/components/columnMenu/columnList.tsx
@@ -23,38 +23,38 @@ import React, { useEffect } from 'react';
* Internal dependencies.
*/
import ColumnListItem from './columnListItem';
-import type { TableOutput } from '../../useTable';
+import { useTable } from '../../useTable';
interface ColumnListProps {
- table: TableOutput;
toggleVisibility: (key: string) => void;
handleClose: () => void;
}
-const ColumnList = ({
- table,
- toggleVisibility,
- handleClose,
-}: ColumnListProps) => {
+const ColumnList = ({ toggleVisibility, handleClose }: ColumnListProps) => {
+ const { hideableColumns, isColumnHidden } = useTable(
+ ({ state, actions }) => ({
+ hideableColumns: state.hideableColumns,
+ isColumnHidden: actions.isColumnHidden,
+ })
+ );
+
useEffect(() => {
return () => {
const visibleColumns: Record = {};
- table.hideableColumns.forEach((column) => {
- visibleColumns[column.header] = table.isColumnHidden(
- column.accessorKey
- );
+ hideableColumns.forEach((column) => {
+ visibleColumns[column.header] = isColumnHidden(column.accessorKey);
});
};
- }, [table, table.hideableColumns]);
+ }, [hideableColumns, isColumnHidden]);
return (
- {table.hideableColumns.map((column, key) => (
+ {hideableColumns.map((column, key) => (
diff --git a/packages/design-system/src/components/table/components/columnMenu/index.tsx b/packages/design-system/src/components/table/components/columnMenu/index.tsx
index 597f4affc..0ec1d075a 100644
--- a/packages/design-system/src/components/table/components/columnMenu/index.tsx
+++ b/packages/design-system/src/components/table/components/columnMenu/index.tsx
@@ -25,16 +25,28 @@ import { createPortal } from 'react-dom';
* Internal dependencies.
*/
import ColumnList from './columnList';
-import { TableOutput } from '../../useTable';
+import { useTable } from '../../useTable';
interface ColumnMenuProps {
- table: TableOutput;
position: { x: number; y: number };
open: boolean;
onClose: (value: boolean) => void;
}
-const ColumnMenu = ({ table, position, open, onClose }: ColumnMenuProps) => {
+const ColumnMenu = ({ position, open, onClose }: ColumnMenuProps) => {
+ const {
+ isColumnHidden,
+ hideColumn,
+ showColumn,
+ toggleVisibility,
+ areAllColumnsVisible,
+ } = useTable(({ state, actions }) => ({
+ isColumnHidden: actions.isColumnHidden,
+ hideColumn: actions.hideColumn,
+ showColumn: actions.showColumn,
+ toggleVisibility: actions.toggleVisibility,
+ areAllColumnsVisible: state.areAllColumnsVisible,
+ }));
const [startAnimation, setStartAnimation] = useState(false);
const timeoutRef = useRef | null>(null);
@@ -78,14 +90,14 @@ const ColumnMenu = ({ table, position, open, onClose }: ColumnMenuProps) => {
{
- table.toggleVisibility();
+ toggleVisibility();
handleClose();
}}
>
✓
@@ -94,11 +106,8 @@ const ColumnMenu = ({ table, position, open, onClose }: ColumnMenuProps) => {
{
- table.isColumnHidden(key)
- ? table.showColumn(key)
- : table.hideColumn(key);
+ isColumnHidden(key) ? showColumn(key) : hideColumn(key);
}}
handleClose={handleClose}
/>
diff --git a/packages/design-system/src/components/table/components/filtersSidebar/chips/chipList.tsx b/packages/design-system/src/components/table/components/filtersSidebar/chips/chipList.tsx
index 477bde755..4c1084aae 100644
--- a/packages/design-system/src/components/table/components/filtersSidebar/chips/chipList.tsx
+++ b/packages/design-system/src/components/table/components/filtersSidebar/chips/chipList.tsx
@@ -22,31 +22,32 @@ import React from 'react';
* Internal dependencies.
*/
import Chip from './chip';
-import type { TableFilter, TableOutput } from '../../../useTable';
+import { useTable } from '../../../useTable';
-interface ChipListProps {
- selectedFilters: TableFilter;
- toggleFilterSelection: TableOutput['toggleFilterSelection'];
-}
+const ChipList = () => {
+ const { selectedFilters, toggleFilterSelection } = useTable(
+ ({ state, actions }) => ({
+ selectedFilters: state.selectedFilters,
+ toggleFilterSelection: actions.toggleFilterSelection,
+ })
+ );
-const ChipList = ({
- selectedFilters,
- toggleFilterSelection,
-}: ChipListProps) => (
-
- {Object.entries(selectedFilters).map(([filterKey, filter]) => {
- return Object.keys(filter.filterValues || {}).map((filterValue) => (
- {
- toggleFilterSelection(filterKey, filterValue, true);
- }}
- />
- ));
- })}
-
-);
+ return (
+
+ {Object.entries(selectedFilters).map(([filterKey, filter]) => {
+ return Object.keys(filter.filterValues || {}).map((filterValue) => (
+ {
+ toggleFilterSelection(filterKey, filterValue, true);
+ }}
+ />
+ ));
+ })}
+
+ );
+};
export default ChipList;
diff --git a/packages/design-system/src/components/table/components/filtersSidebar/chips/index.tsx b/packages/design-system/src/components/table/components/filtersSidebar/chips/index.tsx
index e3029be6d..928bb7e34 100644
--- a/packages/design-system/src/components/table/components/filtersSidebar/chips/index.tsx
+++ b/packages/design-system/src/components/table/components/filtersSidebar/chips/index.tsx
@@ -23,19 +23,14 @@ import React from 'react';
*/
import ChipList from './chipList';
import { StopIcon } from '../../../../../icons';
-import type { TableFilter, TableOutput } from '../../../useTable';
+import { useTable } from '../../../useTable';
-interface ChipsBarProps {
- selectedFilters: TableFilter;
- toggleFilterSelection: TableOutput['toggleFilterSelection'];
- resetFilters: TableOutput['resetFilters'];
-}
+const ChipsBar = () => {
+ const { selectedFilters, resetFilters } = useTable(({ state, actions }) => ({
+ selectedFilters: state.selectedFilters,
+ resetFilters: actions.resetFilters,
+ }));
-const ChipsBar = ({
- selectedFilters,
- toggleFilterSelection,
- resetFilters,
-}: ChipsBarProps) => {
const appliedFiltersCount = Object.values(selectedFilters).reduce(
(acc, filter) => {
acc += Number(Object.keys(filter.filterValues || {}).length);
@@ -62,10 +57,7 @@ const ChipsBar = ({
)}
-
+
);
};
diff --git a/packages/design-system/src/components/table/components/filtersSidebar/index.tsx b/packages/design-system/src/components/table/components/filtersSidebar/index.tsx
index 0d8f64043..2c587f2ea 100644
--- a/packages/design-system/src/components/table/components/filtersSidebar/index.tsx
+++ b/packages/design-system/src/components/table/components/filtersSidebar/index.tsx
@@ -22,21 +22,16 @@ import React, { useCallback, useMemo, useRef, useState } from 'react';
* Internal dependencies.
*/
import ListItem from './listItem';
-import type { TableFilter, TableOutput } from '../../useTable';
+import { useTable } from '../../useTable';
-interface FiltersSidebarProps {
- filters: TableFilter;
- toggleFilterSelection: TableOutput['toggleFilterSelection'];
- toggleSelectAllFilter: TableOutput['toggleSelectAllFilter'];
- isSelectAllFilterSelected: (filterKey: string) => boolean;
-}
+const FiltersSidebar = () => {
+ const { filters, isSelectAllFilterSelected } = useTable(
+ ({ state, actions }) => ({
+ filters: state.filters,
+ isSelectAllFilterSelected: actions.isSelectAllFilterSelected,
+ })
+ );
-const FiltersSidebar = ({
- filters,
- toggleFilterSelection,
- toggleSelectAllFilter,
- isSelectAllFilterSelected,
-}: FiltersSidebarProps) => {
const [expandAll, setExpandAll] = useState(false);
const expandedFilters = useRef(new Set());
const filterKeys = useMemo(() => {
@@ -101,8 +96,6 @@ const FiltersSidebar = ({
key={filterKey}
filter={filter}
filterKey={filterKey}
- toggleFilterSelection={toggleFilterSelection}
- toggleSelectAllFilter={toggleSelectAllFilter}
expandAll={expandAll}
toggleFilterExpansion={toggleFilterExpansion}
isSelectAllFilterSelected={isSelectAllFilterSelected(filterKey)}
diff --git a/packages/design-system/src/components/table/components/filtersSidebar/listItem.tsx b/packages/design-system/src/components/table/components/filtersSidebar/listItem.tsx
index cf9295693..0bba0c264 100644
--- a/packages/design-system/src/components/table/components/filtersSidebar/listItem.tsx
+++ b/packages/design-system/src/components/table/components/filtersSidebar/listItem.tsx
@@ -17,23 +17,17 @@
* External dependencies.
*/
import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import {
- ArrowDown,
- InfoIcon,
- TableFilter,
- TableOutput,
-} from '@ps-analysis-tool/design-system';
+import { ArrowDown, InfoIcon } from '@ps-analysis-tool/design-system';
/**
* Internal dependencies.
*/
import SubList from './subList';
+import { TableFilter } from '../../useTable';
interface ListItemProps {
filter: TableFilter[keyof TableFilter];
filterKey: string;
- toggleFilterSelection: TableOutput['toggleFilterSelection'];
- toggleSelectAllFilter: TableOutput['toggleSelectAllFilter'];
expandAll: boolean;
isSelectAllFilterSelected: boolean;
toggleFilterExpansion: (filterKey: string, expand?: boolean) => void;
@@ -42,12 +36,12 @@ interface ListItemProps {
const ListItem = ({
filter,
filterKey,
- toggleFilterSelection,
- toggleSelectAllFilter,
expandAll,
toggleFilterExpansion,
isSelectAllFilterSelected,
}: ListItemProps) => {
+ const [hasScannedFiltersOnce, setHasScannedFiltersOnce] =
+ useState(true);
const [isExpanded, setExpanded] = useState(false);
const [showSubList, setShowSubList] = useState(false);
@@ -81,6 +75,21 @@ const ListItem = ({
}
}, [expandAll, filterKey, isDisabled, showSubList, toggleFilterExpansion]);
+ useEffect(() => {
+ if (!hasScannedFiltersOnce) {
+ return;
+ }
+
+ const areFiltersSelected = Object.values(filter.filterValues || {}).some(
+ (filterValue) => filterValue.selected
+ );
+
+ if (areFiltersSelected) {
+ setShowSubList(true);
+ setHasScannedFiltersOnce(false);
+ }
+ }, [filter.filterValues, hasScannedFiltersOnce]);
+
return (
@@ -109,10 +118,8 @@ const ListItem = ({
filterValues={filter.filterValues}
filterKey={filterKey}
sort={!filter.hasStaticFilterValues || Boolean(filter.sortValues)}
- toggleFilterSelection={toggleFilterSelection}
isExpanded={isExpanded}
isSelectAllFilterEnabled={Boolean(filter.enableSelectAllOption)}
- toggleSelectAllFilter={toggleSelectAllFilter}
isSelectAllFilterSelected={isSelectAllFilterSelected}
/>
{Number(Object.keys(filter.filterValues || {}).length) > 4 && (
diff --git a/packages/design-system/src/components/table/components/filtersSidebar/option.tsx b/packages/design-system/src/components/table/components/filtersSidebar/option.tsx
index 5d7b17c6c..22100ba8a 100644
--- a/packages/design-system/src/components/table/components/filtersSidebar/option.tsx
+++ b/packages/design-system/src/components/table/components/filtersSidebar/option.tsx
@@ -17,19 +17,14 @@
/**
* External dependencies.
*/
-import React from 'react';
+import React, { useCallback } from 'react';
import classNames from 'classnames';
-/**
- * Internal dependencies.
- */
-import { TableOutput } from '../../useTable';
-
interface OptionProps {
filterKey: string;
filterValue: string;
selected: boolean;
- toggleFilterSelection: TableOutput['toggleFilterSelection'];
+ toggleFilterSelection: (filterKey: string, filterValue: string) => void;
isExpanded: boolean;
}
@@ -39,34 +34,40 @@ const Option = ({
selected,
toggleFilterSelection,
isExpanded,
-}: OptionProps) => (
-
-
- {
- // Use Event Loop to delay the toggleFilterSelection call as too many clicks in a short time provide wrong results
- setTimeout(() => toggleFilterSelection(filterKey, filterValue));
- }}
- />
-
- {String(filterValue)}
-
-
-
-);
+}: OptionProps) => {
+ const handleClick = useCallback(() => {
+ setTimeout(() => toggleFilterSelection(filterKey, filterValue));
+ }, [filterKey, filterValue, toggleFilterSelection]);
+
+ return (
+
+
+
+
+ {String(filterValue)}
+
+
+
+ );
+};
export default Option;
diff --git a/packages/design-system/src/components/table/components/filtersSidebar/subList.tsx b/packages/design-system/src/components/table/components/filtersSidebar/subList.tsx
index 4d337006f..065957f83 100644
--- a/packages/design-system/src/components/table/components/filtersSidebar/subList.tsx
+++ b/packages/design-system/src/components/table/components/filtersSidebar/subList.tsx
@@ -21,7 +21,7 @@ import React, { useMemo } from 'react';
/**
* Internal dependencies.
*/
-import { TableFilter, TableOutput } from '../../useTable';
+import { useTable, type TableFilter } from '../../useTable';
import Option from './option';
interface SubListProps {
@@ -29,9 +29,7 @@ interface SubListProps {
filterKey: string;
sort: boolean;
isExpanded: boolean;
- toggleFilterSelection: TableOutput['toggleFilterSelection'];
isSelectAllFilterEnabled: boolean;
- toggleSelectAllFilter: TableOutput['toggleSelectAllFilter'];
isSelectAllFilterSelected: boolean;
}
@@ -39,12 +37,17 @@ const SubList = ({
filterValues,
filterKey,
sort,
- toggleFilterSelection,
isExpanded,
isSelectAllFilterEnabled,
isSelectAllFilterSelected,
- toggleSelectAllFilter,
}: SubListProps) => {
+ const { toggleFilterSelection, toggleSelectAllFilter } = useTable(
+ ({ actions }) => ({
+ toggleFilterSelection: actions.toggleFilterSelection,
+ toggleSelectAllFilter: actions.toggleSelectAllFilter,
+ })
+ );
+
const sortedFilterValueKeys = useMemo(() => {
if (!sort) {
return Object.keys(filterValues || {});
diff --git a/packages/design-system/src/components/table/components/filtersSidebar/tests/filtersSidebar.tsx b/packages/design-system/src/components/table/components/filtersSidebar/tests/filtersSidebar.tsx
index 220b7f22e..5713167a0 100644
--- a/packages/design-system/src/components/table/components/filtersSidebar/tests/filtersSidebar.tsx
+++ b/packages/design-system/src/components/table/components/filtersSidebar/tests/filtersSidebar.tsx
@@ -19,9 +19,13 @@ import { render, screen, waitFor } from '@testing-library/react';
import FiltersSidebar from '..';
import '@testing-library/jest-dom';
import { act } from 'react-dom/test-utils';
-import { TableFilter } from '../../../useTable';
+import { TableFilter } from '../../../useTable/types';
+import * as table from '../../../useTable/useTable';
describe('FiltersSidebar', () => {
+ const mockUseTable = jest.fn();
+ jest.spyOn(table, 'useTable').mockImplementation(mockUseTable);
+
const initialProps = {
filters: {},
toggleFilterSelection: () => undefined,
@@ -66,7 +70,14 @@ describe('FiltersSidebar', () => {
};
it('should render null', () => {
- render(
);
+ mockUseTable.mockReturnValue({
+ filters: initialProps.filters,
+ isSelectAllFilterSelected: initialProps.isSelectAllFilterSelected,
+ toggleFilterSelection: initialProps.toggleFilterSelection,
+ toggleSelectAllFilter: initialProps.toggleSelectAllFilter,
+ });
+
+ render(
);
const filtersSidebar = screen.queryByTestId('filters-sidebar');
@@ -74,7 +85,14 @@ describe('FiltersSidebar', () => {
});
it('should render a list of filters', () => {
- render(
);
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: props.isSelectAllFilterSelected,
+ toggleFilterSelection: props.toggleFilterSelection,
+ toggleSelectAllFilter: props.toggleSelectAllFilter,
+ });
+
+ render(
);
const filtersSidebar = screen.getByTestId('filters-sidebar');
const filter1 = screen.getByText('Filter 1');
@@ -85,8 +103,15 @@ describe('FiltersSidebar', () => {
expect(filter2).toBeInTheDocument();
});
- it('should show options when clicked on filter', async () => {
- render(
);
+ it('should show options if already selected', async () => {
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: props.isSelectAllFilterSelected,
+ toggleFilterSelection: props.toggleFilterSelection,
+ toggleSelectAllFilter: props.toggleSelectAllFilter,
+ });
+
+ render(
);
const filter1 = screen.getByText('Filter 1');
const filter2 = screen.getByText('Filter 2');
@@ -94,19 +119,29 @@ describe('FiltersSidebar', () => {
expect(filter1).toBeInTheDocument();
expect(filter2).toBeInTheDocument();
- act(() => {
- filter1.click();
- });
-
const value1 = await screen.findByText('value1');
const value2 = await screen.findByText('value2');
expect(value1).toBeInTheDocument();
expect(value2).toBeInTheDocument();
+
+ act(() => {
+ filter1.click();
+ });
+
+ expect(value1).not.toBeInTheDocument();
+ expect(value2).not.toBeInTheDocument();
});
it('should render Filter 3 as disabled', () => {
- render(
);
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: props.isSelectAllFilterSelected,
+ toggleFilterSelection: props.toggleFilterSelection,
+ toggleSelectAllFilter: props.toggleSelectAllFilter,
+ });
+
+ render(
);
const filtersSidebar = screen.getByTestId('filters-sidebar');
const filter3 = screen.getByText('Filter 3');
@@ -117,13 +152,15 @@ describe('FiltersSidebar', () => {
});
it('should show filters in alphabetical order', async () => {
- render(
);
-
- const filter1 = screen.getByText('Filter 1');
- act(() => {
- filter1.click();
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: props.isSelectAllFilterSelected,
+ toggleFilterSelection: props.toggleFilterSelection,
+ toggleSelectAllFilter: props.toggleSelectAllFilter,
});
+ render(
);
+
await waitFor(() => {
const list = screen.getAllByTestId('sub-list-item');
@@ -132,7 +169,14 @@ describe('FiltersSidebar', () => {
});
it('should expand all filters', async () => {
- const { rerender } = render(
);
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: props.isSelectAllFilterSelected,
+ toggleFilterSelection: props.toggleFilterSelection,
+ toggleSelectAllFilter: props.toggleSelectAllFilter,
+ });
+
+ const { rerender } = render(
);
const expandAll = await screen.findByText('Expand All');
act(() => {
@@ -167,25 +211,27 @@ describe('FiltersSidebar', () => {
expect(listExpandArrows[1]).not.toHaveClass('-rotate-90');
});
- rerender(
-
- );
+ title: 'Filter 3',
+ },
+ },
+ isSelectAllFilterSelected: props.isSelectAllFilterSelected,
+ toggleFilterSelection: props.toggleFilterSelection,
+ toggleSelectAllFilter: props.toggleSelectAllFilter,
+ });
+
+ rerender(
);
act(() => {
listExpandArrows[2].click();
@@ -198,7 +244,14 @@ describe('FiltersSidebar', () => {
expect(listExpandArrows[2]).not.toHaveClass('-rotate-90');
});
- rerender(
);
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: props.isSelectAllFilterSelected,
+ toggleFilterSelection: props.toggleFilterSelection,
+ toggleSelectAllFilter: props.toggleSelectAllFilter,
+ });
+
+ rerender(
);
await waitFor(() => {
expect(expandAll.innerHTML).not.toEqual('Expand All');
@@ -228,20 +281,16 @@ describe('FiltersSidebar', () => {
it('should handle select All filter option', async () => {
const toggleSelectAllFilter = jest.fn();
const toggleFilterSelection = jest.fn();
- const { rerender } = render(
-
true}
- />
- );
- const filter1 = screen.getByText('Filter 1');
- act(() => {
- filter1.click();
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: () => true,
+ toggleFilterSelection,
+ toggleSelectAllFilter,
});
+ const { rerender } = render( );
+
const selectAll = await screen.findByText('All');
act(() => {
selectAll.click();
@@ -251,14 +300,14 @@ describe('FiltersSidebar', () => {
expect(toggleSelectAllFilter).toHaveBeenCalledWith('filter1');
});
- rerender(
- false}
- />
- );
+ mockUseTable.mockReturnValue({
+ filters: props.filters,
+ isSelectAllFilterSelected: () => false,
+ toggleFilterSelection,
+ toggleSelectAllFilter,
+ });
+
+ rerender( );
await waitFor(() => {
const filterCheckBoxes = screen.getAllByRole('checkbox');
diff --git a/packages/design-system/src/components/table/components/index.tsx b/packages/design-system/src/components/table/components/index.tsx
index 394f64bcb..e1d05fec7 100644
--- a/packages/design-system/src/components/table/components/index.tsx
+++ b/packages/design-system/src/components/table/components/index.tsx
@@ -19,8 +19,6 @@
*/
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Resizable } from 're-resizable';
-import { saveAs } from 'file-saver';
-import { CookieTableData } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
@@ -28,42 +26,31 @@ import { CookieTableData } from '@ps-analysis-tool/common';
import TableHeader from './tableHeader';
import TableBody from './tableBody';
import ColumnMenu from './columnMenu';
-import { TableData, TableOutput, TableRow } from '../useTable';
+import { useTable } from '../useTable';
import TableTopBar from './tableTopBar';
import ChipsBar from './filtersSidebar/chips';
import FiltersSidebar from './filtersSidebar';
-import { generateCookieTableCSV } from '../utils';
interface TableProps {
- useIsBlockedToHighlight: boolean;
- table: TableOutput;
selectedKey: string | undefined | null;
- getRowObjectKey: (row: TableRow) => string;
- onRowClick: (row: TableData | null) => void;
- onRowContextMenu?: (
- e: React.MouseEvent,
- row: TableRow
- ) => void;
- showTopBar?: boolean;
+ isFiltersSidebarOpen?: boolean;
hideFiltering?: boolean;
- hideExport?: boolean;
- extraInterfaceToTopBar?: React.ReactNode;
+ extraInterfaceToTopBar?: () => React.JSX.Element;
}
const Table = ({
- useIsBlockedToHighlight,
- table,
selectedKey,
- getRowObjectKey,
- onRowClick,
- onRowContextMenu = () => undefined,
- showTopBar = false,
+ isFiltersSidebarOpen = false,
hideFiltering = false,
- hideExport = false,
extraInterfaceToTopBar,
}: TableProps) => {
+ const { tableContainerRef } = useTable(({ state }) => ({
+ tableContainerRef: state.tableContainerRef,
+ }));
+
const [showColumnsMenu, setShowColumnsMenu] = useState(false);
- const [showFilterSidebar, setShowFilterSidebar] = useState(false);
+ const [showFilterSidebar, setShowFilterSidebar] =
+ useState(isFiltersSidebarOpen);
const [columnPosition, setColumnPosition] = useState({
x: 0,
y: 0,
@@ -81,6 +68,7 @@ const Table = ({
}
};
document.addEventListener('click', handleClickOutside, true);
+
return () => {
document.removeEventListener('click', handleClickOutside, true);
};
@@ -103,34 +91,15 @@ const Table = ({
[showColumnsMenu]
);
- const exportCookies = useCallback(() => {
- const cookies = table.rows.map(({ originalData }) => originalData);
- if (cookies.length > 0 && 'parsedCookie' in cookies[0]) {
- const csvTextBlob = generateCookieTableCSV(cookies as CookieTableData[]);
- saveAs(csvTextBlob, 'Cookies Report.csv');
- }
- }, [table.rows]);
-
return (
- {showTopBar && (
-
- )}
-
+
{showFilterSidebar && (
-
+
)}
diff --git a/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx b/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx
index 88532e1df..186525623 100644
--- a/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx
+++ b/packages/design-system/src/components/table/components/tableBody/bodyCell.tsx
@@ -22,17 +22,19 @@ import React from 'react';
/**
* Internal dependencies.
*/
-import type { InfoType, TableRow } from '../../useTable';
+import type { TableRow } from '../../useTable';
interface BodyCellProps {
- cell: React.JSX.Element | InfoType;
+ cell?: () => React.JSX.Element;
width: number;
isHighlighted?: boolean;
isRowFocused: boolean;
row: TableRow;
hasIcon?: boolean;
- showWarningIcon?: boolean | null;
- icon?: () => React.JSX.Element;
+ showIcon?: boolean | null;
+ icon?: {
+ Element: (props: any) => React.JSX.Element;
+ };
onRowClick: (e: React.MouseEvent
) => void;
}
@@ -40,11 +42,14 @@ const BodyCell = ({
cell,
width,
isRowFocused,
+ row,
hasIcon = false,
- showWarningIcon = false,
+ showIcon = false,
icon,
isHighlighted = false,
}: BodyCellProps) => {
+ const IconElement = icon?.Element;
+
return (
{hasIcon && (
- {Boolean(showWarningIcon) && icon?.()}
+ {Boolean(showIcon) && IconElement && (
+
+ )}
)}
- {cell}
+ {cell?.() ?? ''}
);
};
diff --git a/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx b/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx
index 947a1c621..635a10928 100644
--- a/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx
+++ b/packages/design-system/src/components/table/components/tableBody/bodyRow.tsx
@@ -18,8 +18,7 @@
* External dependencies.
*/
import React from 'react';
-import classNames from 'classnames';
-import { CookieTableData } from '@ps-analysis-tool/common';
+import classnames from 'classnames';
/**
* Internal dependencies.
@@ -28,64 +27,39 @@ import BodyCell from './bodyCell';
import type { TableColumn, TableRow } from '../../useTable';
interface BodyRowProps {
- useIsBlockedToHighlight: boolean;
row: TableRow;
columns: TableColumn[];
index: number;
- isRowFocused: boolean;
selectedKey: string | undefined | null;
+ isRowFocused: boolean;
+ getExtraClasses: () => string;
+ hasVerticalBar: boolean;
getRowObjectKey: (row: TableRow) => string;
onRowClick: (e: React.MouseEvent) => void;
onKeyDown: (e: React.KeyboardEvent, index: number) => void;
- onRowContextMenu?: (
+ onRowContextMenu: (
e: React.MouseEvent,
row: TableRow
) => void;
}
-// eslint-disable-next-line complexity
const BodyRow = ({
- useIsBlockedToHighlight,
row,
columns,
index,
selectedKey,
- getRowObjectKey,
isRowFocused,
+ getExtraClasses,
+ hasVerticalBar,
+ getRowObjectKey,
onRowClick,
onKeyDown,
- onRowContextMenu = () => undefined,
+ onRowContextMenu,
}: BodyRowProps) => {
- const cookieKey = getRowObjectKey(row);
- const isBlocked = useIsBlockedToHighlight
- ? (row.originalData as CookieTableData)?.isBlocked
- : Boolean((row.originalData as CookieTableData)?.blockedReasons?.length);
- const isHighlighted = (row.originalData as CookieTableData)?.highlighted;
- const isDomainInAllowList = (row.originalData as CookieTableData)
- ?.isDomainInAllowList;
-
- const tableRowClassName = classNames(
- 'outline-0 flex divide-x divide-american-silver dark:divide-quartz relative',
- isBlocked &&
- (cookieKey !== selectedKey
- ? index % 2
- ? 'dark:bg-flagged-row-even-dark bg-flagged-row-even-light'
- : 'dark:bg-flagged-row-odd-dark bg-flagged-row-odd-light'
- : isRowFocused
- ? 'bg-selection-yellow-dark dark:bg-selection-yellow-light'
- : 'bg-royal-blue text-white dark:bg-medium-persian-blue dark:text-chinese-silver'),
- isDomainInAllowList &&
- !isBlocked &&
- (cookieKey !== selectedKey
- ? index % 2
- ? 'dark:bg-jungle-green-dark bg-leaf-green-dark'
- : 'dark:bg-jungle-green-light bg-leaf-green-light'
- : isRowFocused
- ? 'bg-selection-green-dark dark:bg-selection-green-light'
- : 'bg-royal-blue text-white dark:bg-medium-persian-blue dark:text-chinese-silver'),
- cookieKey !== selectedKey &&
- !isBlocked &&
- !isDomainInAllowList &&
+ const rowKey = getRowObjectKey(row);
+ const isHighlighted = row.originalData?.highlighted;
+ const classes = classnames(
+ rowKey !== selectedKey &&
(index % 2
? isHighlighted
? 'bg-dirty-pink'
@@ -93,9 +67,7 @@ const BodyRow = ({
: isHighlighted
? 'bg-dirty-pink text-dirty-red dark:text-dirty-red text-dirty-red'
: 'bg-white dark:bg-raisin-black'),
- cookieKey === selectedKey &&
- !isBlocked &&
- !isDomainInAllowList &&
+ rowKey === selectedKey &&
(isRowFocused
? isHighlighted
? 'bg-dirty-red'
@@ -104,18 +76,27 @@ const BodyRow = ({
? 'bg-dirty-pink text-dirty-red'
: 'bg-royal-blue text-white dark:bg-medium-persian-blue dark:text-chinese-silver')
);
+ const extraClasses = getExtraClasses();
return (
0,
+ }
+ )}
onClick={onRowClick}
onKeyDown={(e) => onKeyDown(e, index)}
onContextMenu={(e) => onRowContextMenu(e, row)}
data-testid="body-row"
>
- {/* Vertical bar for allow-listed domain row at the left side */}
- {isDomainInAllowList && (
+ {/* Vertical bar for for some indication, styles can also be made dynamic.*/}
+ {hasVerticalBar && (
)}
{columns.map(
@@ -132,18 +113,16 @@ const BodyRow = ({
bodyCellPrefixIcon(row) : undefined
- }
+ icon={bodyCellPrefixIcon ?? undefined}
/>
)
)}
diff --git a/packages/design-system/src/components/table/components/tableBody/index.tsx b/packages/design-system/src/components/table/components/tableBody/index.tsx
index a13ca9b49..3f7e635c7 100644
--- a/packages/design-system/src/components/table/components/tableBody/index.tsx
+++ b/packages/design-system/src/components/table/components/tableBody/index.tsx
@@ -24,35 +24,38 @@ import classNames from 'classnames';
* Internal dependencies.
*/
import BodyRow from './bodyRow';
-import type { TableData, TableOutput, TableRow } from '../../useTable';
+import { useTable } from '../../useTable';
interface TableBodyProps {
- useIsBlockedToHighlight: boolean;
- table: TableOutput;
- getRowObjectKey: (row: TableRow) => string;
isRowFocused: boolean;
setIsRowFocused: (state: boolean) => void;
selectedKey: string | undefined | null;
- onRowClick: (
- key: TableData | null,
- e?: React.MouseEvent
- ) => void;
- onRowContextMenu?: (
- e: React.MouseEvent,
- row: TableRow
- ) => void;
}
const TableBody = ({
- useIsBlockedToHighlight,
- table,
- getRowObjectKey,
isRowFocused,
setIsRowFocused,
selectedKey,
- onRowClick,
- onRowContextMenu = () => undefined,
}: TableBodyProps) => {
+ const {
+ rows,
+ columns,
+ onRowClick,
+ onRowContextMenu,
+ getRowObjectKey,
+ conditionalTableRowClassesHandler,
+ hasVerticalBar,
+ } = useTable(({ state, actions }) => ({
+ rows: state.rows,
+ columns: state.columns,
+ onRowClick: actions.onRowClick,
+ onRowContextMenu: actions.onRowContextMenu,
+ getRowObjectKey: actions.getRowObjectKey,
+ conditionalTableRowClassesHandler:
+ actions.conditionalTableRowClassesHandler,
+ hasVerticalBar: actions.hasVerticalBar,
+ }));
+
const tableBodyRef = useRef(null);
const handleKeyDown = useCallback(
@@ -84,13 +87,13 @@ const TableBody = ({
return;
}
- const newRow = table.rows.find((_, idx) => idx.toString() === newRowId);
+ const newRow = rows.find((_, idx) => idx.toString() === newRowId);
if (newRow) {
onRowClick(newRow?.originalData);
}
},
- [onRowClick, table.rows]
+ [onRowClick, rows]
);
const handleEmptyRowKeyDown = useCallback(
@@ -98,13 +101,13 @@ const TableBody = ({
event.preventDefault();
event.stopPropagation();
- const rowsLength = table.rows.length;
+ const rowsLength = rows.length;
if (event.key === 'ArrowDown' || !rowsLength) {
return;
}
- const newRow = table.rows[rowsLength - 1];
+ const newRow = rows[rowsLength - 1];
// @ts-ignore - the `children` property will be available on the `current` property.
const rowElement = tableBodyRef.current?.children.namedItem(
rowsLength - 1
@@ -118,7 +121,7 @@ const TableBody = ({
rowElement.focus();
onRowClick(newRow?.originalData);
},
- [onRowClick, table.rows]
+ [onRowClick, rows]
);
const tableRowClassName = classNames(
@@ -128,7 +131,7 @@ const TableBody = ({
? 'bg-gainsboro dark:bg-outer-space'
: 'bg-royal-blue text-white dark:bg-medium-persian-blue dark:text-chinese-silver'),
selectedKey !== null &&
- (table.rows.length % 2
+ (rows.length % 2
? 'bg-anti-flash-white dark:bg-charleston-green'
: 'bg-white dark:bg-raisin-black')
);
@@ -138,18 +141,24 @@ const TableBody = ({
ref={tableBodyRef}
className="h-full flex flex-col overflow-x-hidden overflow-y-auto"
>
- {table.rows.map((row, index) => (
+ {rows.map((row, index) => (
) => {
- onRowClick(row?.originalData, e);
+ getExtraClasses={() => {
+ return (
+ conditionalTableRowClassesHandler?.(row, isRowFocused, index) ??
+ ''
+ );
+ }}
+ hasVerticalBar={hasVerticalBar?.(row) ?? false}
+ getRowObjectKey={getRowObjectKey}
+ onRowClick={() => {
+ onRowClick(row?.originalData);
setIsRowFocused(true);
}}
onKeyDown={handleKeyDown}
@@ -166,7 +175,7 @@ const TableBody = ({
}}
onKeyDown={handleEmptyRowKeyDown}
>
- {table.columns.map(({ width }, index) => (
+ {columns.map(({ width }, index) => (
- {table.columns.map(({ width }, index) => (
+ {columns.map(({ width }, index) => (
{
it('should render Body Cell component', () => {
render(
'.example.com'}
width={50}
isRowFocused={bodyCellProp.isRowFocused}
// @ts-ignore
diff --git a/packages/design-system/src/components/table/components/tableBody/tests/bodyRow.tsx b/packages/design-system/src/components/table/components/tableBody/tests/bodyRow.tsx
index 5c0572407..8c9145b81 100644
--- a/packages/design-system/src/components/table/components/tableBody/tests/bodyRow.tsx
+++ b/packages/design-system/src/components/table/components/tableBody/tests/bodyRow.tsx
@@ -42,7 +42,7 @@ describe('BodyRow', () => {
onRowClick: jest.fn(() => {
BodyRowProp.isRowFocused = true;
}),
- onKeyDown: jest.fn(),
+ onKeyDown: () => '',
domainsInAllowList: emptySet,
setDomainsInAllowList: jest.fn((domains: Set) => {
BodyRowProp.domainsInAllowList = domains;
@@ -66,6 +66,7 @@ describe('BodyRow', () => {
columns={BodyRowProp.columns}
selectedKey={BodyRowProp.selectedKey}
getRowObjectKey={BodyRowProp.getRowObjectKey}
+ getExtraClasses={() => ''}
isRowFocused={BodyRowProp.isRowFocused}
onRowClick={BodyRowProp.onRowClick}
onKeyDown={BodyRowProp.onKeyDown}
@@ -100,6 +101,7 @@ describe('BodyRow', () => {
columns={BodyRowProp.columns}
selectedKey={BodyRowProp.selectedKey}
getRowObjectKey={BodyRowProp.getRowObjectKey}
+ getExtraClasses={() => ''}
isRowFocused={BodyRowProp.isRowFocused}
onRowClick={BodyRowProp.onRowClick}
onKeyDown={BodyRowProp.onKeyDown}
diff --git a/packages/design-system/src/components/table/components/tableBody/tests/index.tsx b/packages/design-system/src/components/table/components/tableBody/tests/index.tsx
index 494e54cb0..405fed864 100644
--- a/packages/design-system/src/components/table/components/tableBody/tests/index.tsx
+++ b/packages/design-system/src/components/table/components/tableBody/tests/index.tsx
@@ -26,6 +26,7 @@ import '@testing-library/jest-dom';
*/
import TableBody from '..';
import table from '../../../../../test-data/cookieTableMockData';
+import * as useTable from '../../../useTable/useTable';
const bodyRowProp = {
row: table.rows[0],
@@ -47,6 +48,9 @@ const getRowObjectKey = jest.fn((row) => {
});
describe('TableBody', () => {
+ const mockUseTable = jest.fn();
+ jest.spyOn(useTable, 'useTable').mockImplementation(mockUseTable);
+
beforeAll(() => {
globalThis.chrome = SinonChrome as unknown as typeof chrome;
});
@@ -56,18 +60,21 @@ describe('TableBody', () => {
});
it('should render Table Body component', () => {
+ mockUseTable.mockReturnValue({
+ rows: table.rows,
+ columns: table.columns,
+ onRowClick,
+ onRowContextMenu: jest.fn(),
+ getRowObjectKey,
+ conditionalTableRowClassesHandler: jest.fn(),
+ hasVerticalBar: () => false,
+ });
+
render(
{
- onRowClick(bodyRowProp.row?.originalData);
- setIsRowFocused(true);
- }}
/>
);
@@ -95,18 +102,21 @@ describe('TableBody', () => {
});
it('should update focused row', () => {
+ mockUseTable.mockReturnValue({
+ rows: table.rows,
+ columns: table.columns,
+ onRowClick,
+ onRowContextMenu: jest.fn(),
+ getRowObjectKey,
+ conditionalTableRowClassesHandler: jest.fn(),
+ hasVerticalBar: () => false,
+ });
+
render(
{
- onRowClick(bodyRowProp.row?.originalData);
- setIsRowFocused(true);
- }}
/>
);
diff --git a/packages/design-system/src/components/table/components/tableHeader/headerCell.tsx b/packages/design-system/src/components/table/components/tableHeader/headerCell.tsx
index c02082c57..5399f0f5d 100644
--- a/packages/design-system/src/components/table/components/tableHeader/headerCell.tsx
+++ b/packages/design-system/src/components/table/components/tableHeader/headerCell.tsx
@@ -22,25 +22,29 @@ import React, { useCallback, useRef } from 'react';
* Internal dependencies.
*/
import HeaderResizer from './headerResizer';
-import type { TableColumn, TableOutput } from '../../useTable';
+import { useTable, type TableColumn } from '../../useTable';
import { ArrowDown } from '../../../../icons';
interface HeaderCellProps {
- table: TableOutput;
index: number;
cell: TableColumn;
setIsRowFocused: (state: boolean) => void;
}
-const HeaderCell = ({
- table,
- index,
- cell,
- setIsRowFocused,
-}: HeaderCellProps) => {
+const HeaderCell = ({ index, cell, setIsRowFocused }: HeaderCellProps) => {
+ const { sortKey, sortOrder, isResizing, setSortKey, onMouseDown } = useTable(
+ ({ state, actions }) => ({
+ sortKey: state.sortKey,
+ sortOrder: state.sortOrder,
+ isResizing: state.isResizing,
+ setSortKey: actions.setSortKey,
+ onMouseDown: actions.onMouseDown,
+ })
+ );
+
const handleOnClick = useCallback(() => {
- table.setSortKey(cell.accessorKey);
- }, [cell.accessorKey, table]);
+ setSortKey(cell.accessorKey);
+ }, [cell.accessorKey, setSortKey]);
const columnRef = useRef(null);
@@ -48,9 +52,9 @@ const HeaderCell = ({
@@ -61,16 +65,16 @@ const HeaderCell = ({
>
{cell.header}
- {table.sortKey === cell.accessorKey &&
+ {sortKey === cell.accessorKey &&
{
asc: ,
desc: ,
- }[table.sortOrder]}
+ }[sortOrder]}
{
- table.onMouseDown(columnRef, index);
+ onMouseDown(columnRef, index);
}}
/>
diff --git a/packages/design-system/src/components/table/components/tableHeader/headerRow.tsx b/packages/design-system/src/components/table/components/tableHeader/headerRow.tsx
index 457a36b82..17b65c4d0 100644
--- a/packages/design-system/src/components/table/components/tableHeader/headerRow.tsx
+++ b/packages/design-system/src/components/table/components/tableHeader/headerRow.tsx
@@ -22,21 +22,23 @@ import React from 'react';
* Internal dependencies.
*/
import HeaderCell from './headerCell';
-import type { TableOutput } from '../../useTable';
+import { useTable } from '../../useTable';
interface HeaderRowProps {
- table: TableOutput;
setIsRowFocused: (state: boolean) => void;
}
-const HeaderRow = ({ table, setIsRowFocused }: HeaderRowProps) => {
+const HeaderRow = ({ setIsRowFocused }: HeaderRowProps) => {
+ const { columns } = useTable(({ state }) => ({
+ columns: state.columns,
+ }));
+
return (
- {table.columns?.map((cell, idx) => (
+ {columns?.map((cell, idx) => (
diff --git a/packages/design-system/src/components/table/components/tableHeader/index.tsx b/packages/design-system/src/components/table/components/tableHeader/index.tsx
index 7ceb19918..623b430c8 100644
--- a/packages/design-system/src/components/table/components/tableHeader/index.tsx
+++ b/packages/design-system/src/components/table/components/tableHeader/index.tsx
@@ -22,10 +22,8 @@ import React, { useCallback } from 'react';
* Internal dependencies.
*/
import HeaderRow from './headerRow';
-import type { TableOutput } from '../../useTable';
interface TableHeaderProps {
- table: TableOutput;
setColumnPosition: (position: { x: number; y: number }) => void;
onRightClick: (
event: React.MouseEvent
@@ -34,7 +32,6 @@ interface TableHeaderProps {
}
const TableHeader = ({
- table,
setColumnPosition,
onRightClick,
setIsRowFocused,
@@ -52,7 +49,7 @@ const TableHeader = ({
return (
-
+
);
};
diff --git a/packages/design-system/src/components/table/components/tableTopBar/index.tsx b/packages/design-system/src/components/table/components/tableTopBar/index.tsx
index 2a713014a..d83aa5fda 100644
--- a/packages/design-system/src/components/table/components/tableTopBar/index.tsx
+++ b/packages/design-system/src/components/table/components/tableTopBar/index.tsx
@@ -18,42 +18,38 @@
*/
import React, { useCallback } from 'react';
import classNames from 'classnames';
-import {
- FilterIcon,
- SearchInput,
- TableOutput,
-} from '@ps-analysis-tool/design-system';
+import { FilterIcon, SearchInput } from '@ps-analysis-tool/design-system';
/**
* Internal dependencies.
*/
import ExportButton from '../../../exportButton';
+import { useTable } from '../../useTable';
interface TableTopBarProps {
- searchValue: TableOutput['searchValue'];
- setSearchValue: TableOutput['setSearchValue'];
showFilterSidebar: boolean;
setShowFilterSidebar: React.Dispatch>;
- cookiesCount: number;
hideFiltering?: boolean;
disableFiltering?: boolean;
- disableExport?: boolean;
- extraInterface?: React.ReactNode;
- exportCookies?: () => void;
+ extraInterface?: () => React.JSX.Element;
}
const TableTopBar = ({
- searchValue,
- setSearchValue,
showFilterSidebar,
setShowFilterSidebar,
- cookiesCount,
hideFiltering = false,
disableFiltering = false,
- disableExport = false,
- extraInterface = null,
- exportCookies,
+ extraInterface,
}: TableTopBarProps) => {
+ const { rows, searchValue, setSearchValue, exportTableData } = useTable(
+ ({ state, actions }) => ({
+ rows: state.rows,
+ searchValue: state.searchValue,
+ setSearchValue: actions.setSearchValue,
+ exportTableData: actions.exportTableData,
+ })
+ );
+
const handleInput = useCallback(
(event: React.ChangeEvent) => {
setSearchValue(event.target.value);
@@ -91,18 +87,18 @@ const TableTopBar = ({
- {extraInterface}
- {exportCookies && (
+ {extraInterface?.()}
+ {exportTableData && (
exportTableData(rows)}
/>
)}
- Count: {cookiesCount ?? 0}
+ Count: {rows.length ?? 0}
);
diff --git a/packages/design-system/src/components/table/index.ts b/packages/design-system/src/components/table/index.ts
index 02fb2f9a7..1bf0a60aa 100644
--- a/packages/design-system/src/components/table/index.ts
+++ b/packages/design-system/src/components/table/index.ts
@@ -15,6 +15,6 @@
*/
export { default as Table } from './components';
-export { default as useTable } from './useTable';
export * from './persistentSettingsStore';
export * from './useTable';
+export * from './utils';
diff --git a/packages/design-system/src/components/table/persistentSettingsStore/index.tsx b/packages/design-system/src/components/table/persistentSettingsStore/index.tsx
index f5dce1724..86b10ecef 100644
--- a/packages/design-system/src/components/table/persistentSettingsStore/index.tsx
+++ b/packages/design-system/src/components/table/persistentSettingsStore/index.tsx
@@ -24,8 +24,8 @@ import React, {
useMemo,
useRef,
} from 'react';
-import { useContextSelector, createContext } from 'use-context-selector';
import PQueue from 'p-queue';
+import { useContextSelector, createContext } from '@ps-analysis-tool/common';
/**
* Internal dependencies
diff --git a/packages/design-system/src/components/table/persistentSettingsStore/utils/extractStorage.ts b/packages/design-system/src/components/table/persistentSettingsStore/utils/extractStorage.ts
index 6817d0d41..09ea92c6c 100644
--- a/packages/design-system/src/components/table/persistentSettingsStore/utils/extractStorage.ts
+++ b/packages/design-system/src/components/table/persistentSettingsStore/utils/extractStorage.ts
@@ -45,14 +45,12 @@ const extractChromeStorage = async (
): Promise
=> {
const tabId = chrome.devtools.inspectedWindow.tabId.toString();
- const data = await chrome.storage.local.get();
- const tableData = data?.[tabId];
+ const data = await chrome.storage.session.get();
+ const tableData = data?.[tabId + persistenceKey];
if (tableData) {
- const persistenceData = tableData?.[persistenceKey];
- if (persistenceData) {
- return persistenceData;
- }
+ return tableData;
}
+
return {} as TablePersistentSettingsStoreContext['state'];
};
diff --git a/packages/design-system/src/components/table/persistentSettingsStore/utils/updateStorage.ts b/packages/design-system/src/components/table/persistentSettingsStore/utils/updateStorage.ts
index ae2c116e4..3d1e35436 100644
--- a/packages/design-system/src/components/table/persistentSettingsStore/utils/updateStorage.ts
+++ b/packages/design-system/src/components/table/persistentSettingsStore/utils/updateStorage.ts
@@ -93,10 +93,10 @@ const updateChromeStorage = async (
}
const tabId = chrome.devtools.inspectedWindow.tabId.toString();
- const data = await chrome.storage.local.get();
+ const data = await chrome.storage.session.get();
let tableData: TablePersistentSettingsStoreContext['state'] =
- data?.[tabId]?.[TABLE_PERSISTENT_SETTINGS_STORE_KEY];
+ data?.[tabId + TABLE_PERSISTENT_SETTINGS_STORE_KEY];
let requiredData = tableData?.[persistenceKey];
if (requiredData) {
@@ -108,9 +108,9 @@ const updateChromeStorage = async (
requiredData = storageData;
}
- if (!tableData && data[tabId]) {
- data[tabId][TABLE_PERSISTENT_SETTINGS_STORE_KEY] = {};
- tableData = data[tabId][TABLE_PERSISTENT_SETTINGS_STORE_KEY];
+ if (!tableData) {
+ data[tabId + TABLE_PERSISTENT_SETTINGS_STORE_KEY] = {};
+ tableData = data[tabId + TABLE_PERSISTENT_SETTINGS_STORE_KEY];
}
if (tableData && !tableData[persistenceKey]) {
@@ -120,7 +120,7 @@ const updateChromeStorage = async (
tableData[persistenceKey] = requiredData;
}
- await chrome.storage.local.set(data);
+ await chrome.storage.session.set(data);
return tableData;
};
diff --git a/packages/design-system/src/components/table/useTable/context.ts b/packages/design-system/src/components/table/useTable/context.ts
new file mode 100644
index 000000000..b0d493340
--- /dev/null
+++ b/packages/design-system/src/components/table/useTable/context.ts
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { createContext, noop } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import {
+ TableColumn,
+ TableFilter,
+ TableRow,
+ TableProviderProps,
+} from './types';
+import { ColumnResizingOutput } from './useColumnResizing';
+import { ColumnSortingOutput } from './useColumnSorting';
+import { ColumnVisibilityOutput } from './useColumnVisibility';
+import { TableFilteringOutput } from './useFiltering';
+import { TableSearchOutput } from './useSearch';
+
+export interface TableStoreContext {
+ state: {
+ columns: TableColumn[];
+ hideableColumns: TableColumn[];
+ rows: TableRow[];
+ sortKey: ColumnSortingOutput['sortKey'];
+ sortOrder: ColumnSortingOutput['sortOrder'];
+ areAllColumnsVisible: ColumnVisibilityOutput['areAllColumnsVisible'];
+ tableContainerRef: ColumnResizingOutput['tableContainerRef'];
+ isResizing: ColumnResizingOutput['isResizing'];
+ filters: TableFilter;
+ selectedFilters: TableFilter;
+ isFiltering: TableFilteringOutput['isFiltering'];
+ searchValue: TableSearchOutput['searchValue'];
+ };
+ actions: {
+ setSortKey: ColumnSortingOutput['setSortKey'];
+ setSortOrder: ColumnSortingOutput['setSortOrder'];
+ hideColumn: ColumnVisibilityOutput['hideColumn'];
+ toggleVisibility: ColumnVisibilityOutput['toggleVisibility'];
+ showColumn: ColumnVisibilityOutput['showColumn'];
+ isColumnHidden: ColumnVisibilityOutput['isColumnHidden'];
+ onMouseDown: ColumnResizingOutput['onMouseDown'];
+ toggleFilterSelection: TableFilteringOutput['toggleFilterSelection'];
+ toggleSelectAllFilter: TableFilteringOutput['toggleSelectAllFilter'];
+ resetFilters: TableFilteringOutput['resetFilters'];
+ isSelectAllFilterSelected: TableFilteringOutput['isSelectAllFilterSelected'];
+ setSearchValue: TableSearchOutput['setSearchValue'];
+ onRowClick: TableProviderProps['onRowClick'];
+ onRowContextMenu: TableProviderProps['onRowContextMenu'];
+ getRowObjectKey: TableProviderProps['getRowObjectKey'];
+ conditionalTableRowClassesHandler?: TableProviderProps['conditionalTableRowClassesHandler'];
+ exportTableData?: TableProviderProps['exportTableData'];
+ hasVerticalBar?: TableProviderProps['hasVerticalBar'];
+ };
+}
+
+const initialState: TableStoreContext = {
+ state: {
+ columns: [],
+ hideableColumns: [],
+ rows: [],
+ sortKey: '',
+ sortOrder: 'asc',
+ areAllColumnsVisible: true,
+ tableContainerRef: null,
+ isResizing: false,
+ filters: {},
+ selectedFilters: {},
+ isFiltering: false,
+ searchValue: '',
+ },
+ actions: {
+ setSortKey: noop,
+ setSortOrder: noop,
+ hideColumn: noop,
+ toggleVisibility: noop,
+ showColumn: noop,
+ isColumnHidden: () => false,
+ onMouseDown: noop,
+ toggleFilterSelection: noop,
+ toggleSelectAllFilter: noop,
+ resetFilters: noop,
+ isSelectAllFilterSelected: () => false,
+ setSearchValue: noop,
+ onRowClick: noop,
+ onRowContextMenu: noop,
+ getRowObjectKey: () => '',
+ },
+};
+
+export const TableContext = createContext(initialState);
diff --git a/packages/design-system/src/components/table/useTable/index.ts b/packages/design-system/src/components/table/useTable/index.ts
new file mode 100644
index 000000000..230ace481
--- /dev/null
+++ b/packages/design-system/src/components/table/useTable/index.ts
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export * from './provider';
+export * from './types';
+export * from './useTable';
diff --git a/packages/design-system/src/components/table/useTable/index.tsx b/packages/design-system/src/components/table/useTable/index.tsx
deleted file mode 100644
index a632a5f65..000000000
--- a/packages/design-system/src/components/table/useTable/index.tsx
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * External dependencies.
- */
-import { useMemo } from 'react';
-import {
- getValueByKey,
- CookieTableData,
- TechnologyData,
-} from '@ps-analysis-tool/common';
-/**
- * Internal dependencies.
- */
-import useColumnSorting, { type ColumnSortingOutput } from './useColumnSorting';
-import useColumnVisibility, {
- type ColumnVisibilityOutput,
-} from './useColumnVisibility';
-import useColumnResizing, {
- type ColumnResizingOutput,
-} from './useColumnResizing';
-import useFiltering, { TableFilteringOutput } from './useFiltering';
-import useSearch, { TableSearchOutput } from './useSearch';
-
-export type TableData = CookieTableData | TechnologyData;
-
-export type InfoType = number | string | boolean | Array | [];
-
-export type TableColumn = {
- header: string;
- accessorKey: string;
- cell?: (info: InfoType, details?: TableData) => React.JSX.Element | InfoType;
- enableHiding?: boolean;
- isHiddenByDefault?: boolean;
- enableBodyCellPrefixIcon?: boolean;
- bodyCellPrefixIcon?: (row: TableRow) => React.JSX.Element;
- showBodyCellPrefixIcon?: (row: TableRow) => boolean;
- widthWeightagePercentage?: number;
- width?: number; // For internal use only
-};
-
-export type TableRow = {
- [accessorKey: string]: {
- value: React.JSX.Element | InfoType;
- };
- //@ts-ignore
- originalData: TableData;
-};
-
-export type TableFilter = {
- [accessorKey: string]: {
- title: string;
- description?: string;
- hasStaticFilterValues?: boolean;
- hasPrecalculatedFilterValues?: boolean;
- enableSelectAllOption?: boolean;
- filterValues?: {
- [filterValue: string]: {
- selected: boolean;
- description?: string;
- };
- };
- sortValues?: boolean; // for dynamic filters, values are sorted by default even if not specified.
- useGenericPersistenceKey?: boolean;
- calculateFilterValues?: (value: InfoType) => string;
- comparator?: (value: InfoType, filterValue: string) => boolean;
- };
-};
-
-export type PersistentStorageData = {
- columnsVisibility?: { [key: string]: boolean };
- columnsSizing?: { [key: string]: number };
- sortBy?: string;
- sortOrder?: 'asc' | 'desc';
- selectedFilters?: {
- [key: string]: TableFilter[keyof TableFilter]['filterValues'];
- };
- searchValue?: string;
-};
-
-export type TableOutput = {
- columns: TableColumn[];
- hideableColumns: TableColumn[];
- rows: TableRow[];
- sortKey: ColumnSortingOutput['sortKey'];
- sortOrder: ColumnSortingOutput['sortOrder'];
- setSortKey: ColumnSortingOutput['setSortKey'];
- setSortOrder: ColumnSortingOutput['setSortOrder'];
- hideColumn: ColumnVisibilityOutput['hideColumn'];
- toggleVisibility: ColumnVisibilityOutput['toggleVisibility'];
- areAllColumnsVisible: ColumnVisibilityOutput['areAllColumnsVisible'];
- showColumn: ColumnVisibilityOutput['showColumn'];
- isColumnHidden: ColumnVisibilityOutput['isColumnHidden'];
- tableContainerRef: ColumnResizingOutput['tableContainerRef'];
- onMouseDown: ColumnResizingOutput['onMouseDown'];
- isResizing: ColumnResizingOutput['isResizing'];
- filters: TableFilter;
- selectedFilters: TableFilter;
- isFiltering: TableFilteringOutput['isFiltering'];
- toggleFilterSelection: TableFilteringOutput['toggleFilterSelection'];
- toggleSelectAllFilter: TableFilteringOutput['toggleSelectAllFilter'];
- resetFilters: TableFilteringOutput['resetFilters'];
- isSelectAllFilterSelected: TableFilteringOutput['isSelectAllFilterSelected'];
- searchValue: TableSearchOutput['searchValue'];
- setSearchValue: TableSearchOutput['setSearchValue'];
-};
-
-interface useTableProps {
- data: TableData[];
- tableColumns: TableColumn[];
- tableFilterData?: TableFilter;
- tableSearchKeys?: string[];
- tablePersistentSettingsKey?: string;
-}
-
-const useTable = ({
- data,
- tableColumns,
- tableFilterData,
- tableSearchKeys,
- tablePersistentSettingsKey,
-}: useTableProps): TableOutput => {
- const commonKey = useMemo(() => {
- if (!tablePersistentSettingsKey) {
- return undefined;
- }
-
- const keys = tablePersistentSettingsKey.split('#');
-
- return keys[0];
- }, [tablePersistentSettingsKey]);
-
- const {
- visibleColumns,
- hideColumn,
- toggleVisibility,
- areAllColumnsVisible,
- showColumn,
- isColumnHidden,
- } = useColumnVisibility(tableColumns, commonKey);
-
- const allTableColumnsKeys = useMemo(() => {
- return tableColumns.map(({ accessorKey }) => accessorKey);
- }, [tableColumns]);
-
- const { columns, tableContainerRef, onMouseDown, isResizing } =
- useColumnResizing(visibleColumns, allTableColumnsKeys, commonKey);
-
- const { sortedData, sortKey, sortOrder, setSortKey, setSortOrder } =
- useColumnSorting(data, commonKey);
-
- const {
- filters,
- selectedFilters,
- filteredData,
- isFiltering,
- toggleFilterSelection,
- toggleSelectAllFilter,
- resetFilters,
- isSelectAllFilterSelected,
- } = useFiltering(
- sortedData,
- tableFilterData,
- tablePersistentSettingsKey,
- commonKey
- );
-
- const { searchValue, setSearchValue, searchFilteredData } = useSearch(
- filteredData,
- tableSearchKeys,
- commonKey
- );
-
- const rows = useMemo(() => {
- return searchFilteredData.map((_data) => {
- const row = {
- originalData: _data,
- } as TableRow;
-
- columns.forEach((column) => {
- const value = getValueByKey(column.accessorKey, _data);
- row[column.accessorKey] = {
- value: column.cell?.(value, _data) ?? value,
- };
- });
-
- return row;
- });
- }, [searchFilteredData, columns]);
-
- const hideableColumns = useMemo(
- () => tableColumns.filter((column) => column.enableHiding !== false),
- [tableColumns]
- );
-
- return {
- columns,
- hideableColumns,
- rows,
- sortKey,
- sortOrder,
- setSortKey,
- setSortOrder,
- hideColumn,
- toggleVisibility,
- areAllColumnsVisible,
- showColumn,
- isColumnHidden,
- tableContainerRef,
- onMouseDown,
- isResizing,
- filters,
- selectedFilters,
- isFiltering,
- toggleFilterSelection,
- toggleSelectAllFilter,
- resetFilters,
- isSelectAllFilterSelected,
- searchValue,
- setSearchValue,
- };
-};
-
-export default useTable;
diff --git a/packages/design-system/src/components/table/useTable/provider.tsx b/packages/design-system/src/components/table/useTable/provider.tsx
new file mode 100644
index 000000000..0ecdcd5b8
--- /dev/null
+++ b/packages/design-system/src/components/table/useTable/provider.tsx
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import React, { PropsWithChildren, useEffect, useMemo, useState } from 'react';
+import { getValueByKey } from '@ps-analysis-tool/common';
+/**
+ * Internal dependencies.
+ */
+import useColumnSorting from './useColumnSorting';
+import useColumnVisibility from './useColumnVisibility';
+import useColumnResizing from './useColumnResizing';
+import useFiltering from './useFiltering';
+import useSearch from './useSearch';
+import { TableContext } from './context';
+import { TableRow, TableProviderProps } from './types';
+
+export const TableProvider = ({
+ data,
+ tableColumns,
+ tableFilterData,
+ tableSearchKeys,
+ tablePersistentSettingsKey,
+ onRowClick,
+ onRowContextMenu,
+ getRowObjectKey,
+ conditionalTableRowClassesHandler,
+ exportTableData,
+ hasVerticalBar,
+ isRowSelected,
+ children,
+}: PropsWithChildren) => {
+ const commonKey = useMemo(() => {
+ if (!tablePersistentSettingsKey) {
+ return undefined;
+ }
+
+ const keys = tablePersistentSettingsKey.split('#');
+
+ return keys[0];
+ }, [tablePersistentSettingsKey]);
+
+ const {
+ visibleColumns,
+ hideColumn,
+ toggleVisibility,
+ areAllColumnsVisible,
+ showColumn,
+ isColumnHidden,
+ } = useColumnVisibility(tableColumns, commonKey);
+
+ const allTableColumnsKeys = useMemo(() => {
+ return tableColumns.map(({ accessorKey }) => accessorKey);
+ }, [tableColumns]);
+
+ const { columns, tableContainerRef, onMouseDown, isResizing } =
+ useColumnResizing(visibleColumns, allTableColumnsKeys, commonKey);
+
+ const { sortedData, sortKey, sortOrder, setSortKey, setSortOrder } =
+ useColumnSorting(data, commonKey);
+
+ const {
+ filters,
+ selectedFilters,
+ filteredData,
+ isFiltering,
+ toggleFilterSelection,
+ toggleSelectAllFilter,
+ resetFilters,
+ isSelectAllFilterSelected,
+ } = useFiltering(
+ sortedData,
+ tableFilterData,
+ tablePersistentSettingsKey,
+ commonKey
+ );
+
+ const { searchValue, setSearchValue, searchFilteredData } = useSearch(
+ filteredData,
+ tableSearchKeys,
+ commonKey
+ );
+
+ const [rows, setRows] = useState([]);
+
+ useEffect(() => {
+ const newRows = searchFilteredData.map((_data) => {
+ const row = {
+ originalData: _data,
+ } as TableRow;
+
+ columns.forEach((column) => {
+ const value = getValueByKey(column.accessorKey, _data);
+ row[column.accessorKey] = {
+ value: () => column.cell(value, _data) as React.JSX.Element,
+ };
+ });
+
+ return row;
+ });
+
+ setRows(newRows);
+ }, [searchFilteredData, columns]);
+
+ const hideableColumns = useMemo(
+ () => tableColumns.filter((column) => column.enableHiding !== false),
+ [tableColumns]
+ );
+
+ useEffect(() => {
+ const filteredRows = rows.filter(
+ (row) => isRowSelected?.(row.originalData) ?? true
+ );
+
+ if (filteredRows.length === 0) {
+ onRowClick(null);
+ }
+ }, [isRowSelected, onRowClick, rows]);
+ return (
+
+ {children}
+
+ );
+};
diff --git a/packages/design-system/src/components/table/useTable/types.ts b/packages/design-system/src/components/table/useTable/types.ts
new file mode 100644
index 000000000..aef022f07
--- /dev/null
+++ b/packages/design-system/src/components/table/useTable/types.ts
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { CookieTableData, TechnologyData } from '@ps-analysis-tool/common';
+
+export type TableData = (CookieTableData | TechnologyData) & {
+ highlighted?: boolean;
+};
+
+export type InfoType = number | string | boolean | Array | [];
+
+export type TableColumn = {
+ header: string;
+ accessorKey: string;
+ cell: (info: InfoType, details?: TableData) => React.JSX.Element | InfoType;
+ enableHiding?: boolean;
+ isHiddenByDefault?: boolean;
+ enableBodyCellPrefixIcon?: boolean;
+ bodyCellPrefixIcon?: {
+ Element: (props: any) => React.JSX.Element;
+ };
+ showBodyCellPrefixIcon?: (row: TableRow) => boolean;
+ widthWeightagePercentage?: number;
+ width?: number; // For internal use only
+};
+
+export type TableRow = {
+ [accessorKey: string]: {
+ value: () => React.JSX.Element;
+ };
+ //@ts-ignore
+ originalData: TableData;
+};
+
+export type TableFilter = {
+ [accessorKey: string]: {
+ title: string;
+ description?: string;
+ hasStaticFilterValues?: boolean;
+ hasPrecalculatedFilterValues?: boolean;
+ enableSelectAllOption?: boolean;
+ isSelectAllOptionSelected?: boolean;
+ filterValues?: {
+ [filterValue: string]: {
+ selected: boolean;
+ description?: string;
+ };
+ };
+ sortValues?: boolean; // for dynamic filters, values are sorted by default even if not specified.
+ useGenericPersistenceKey?: boolean;
+ calculateFilterValues?: (value: InfoType) => string;
+ comparator?: (value: InfoType, filterValue: string) => boolean;
+ };
+};
+
+export type PersistentStorageData = {
+ columnsVisibility?: { [key: string]: boolean };
+ columnsSizing?: { [key: string]: number };
+ sortBy?: string;
+ sortOrder?: 'asc' | 'desc';
+ selectedFilters?: {
+ [key: string]: TableFilter[keyof TableFilter]['filterValues'];
+ };
+ searchValue?: string;
+};
+
+export interface TableProviderProps {
+ data: TableData[];
+ tableColumns: TableColumn[];
+ tableFilterData?: TableFilter;
+ tableSearchKeys?: string[];
+ tablePersistentSettingsKey?: string;
+ onRowClick: (row: TableData | null) => void;
+ onRowContextMenu: (
+ e: React.MouseEvent,
+ row: TableRow
+ ) => void;
+ getRowObjectKey: (row: TableRow) => string;
+ conditionalTableRowClassesHandler?: (
+ row: TableRow,
+ isRowFocused: boolean,
+ rowIndex: number
+ ) => string;
+ exportTableData?: (rows: TableRow[]) => void;
+ hasVerticalBar?: (row: TableRow) => boolean;
+ isRowSelected?: (cookie: TableData | null) => boolean;
+}
diff --git a/packages/design-system/src/components/table/useTable/useColumnResizing/handleResizeOnColumnsVisibilityChange.ts b/packages/design-system/src/components/table/useTable/useColumnResizing/handleResizeOnColumnsVisibilityChange.ts
index 4541e479f..9e5cef328 100644
--- a/packages/design-system/src/components/table/useTable/useColumnResizing/handleResizeOnColumnsVisibilityChange.ts
+++ b/packages/design-system/src/components/table/useTable/useColumnResizing/handleResizeOnColumnsVisibilityChange.ts
@@ -17,7 +17,7 @@
/**
* Internal dependencies
*/
-import { TableColumn } from '..';
+import { TableColumn } from '../types';
import { resizeColumns } from './resizeColumns';
const getInitialColumnSize = (
diff --git a/packages/design-system/src/components/table/useTable/useColumnResizing/index.tsx b/packages/design-system/src/components/table/useTable/useColumnResizing/index.tsx
index 8bba2015f..7cb70b58c 100644
--- a/packages/design-system/src/components/table/useTable/useColumnResizing/index.tsx
+++ b/packages/design-system/src/components/table/useTable/useColumnResizing/index.tsx
@@ -22,14 +22,14 @@ import { useCallback, useEffect, useRef, useState } from 'react';
/**
* Internal dependencies.
*/
-import type { PersistentStorageData, TableColumn } from '..';
+import type { PersistentStorageData, TableColumn } from '../types';
import { useTablePersistentSettingsStore } from '../../persistentSettingsStore';
import { resizeColumns } from './resizeColumns';
import { handleResizeOnColumnsVisibilityChange } from './handleResizeOnColumnsVisibilityChange';
export type ColumnResizingOutput = {
columns: TableColumn[];
- tableContainerRef: React.RefObject;
+ tableContainerRef: React.RefObject | null;
onMouseDown: (
selectedColumnRef: React.RefObject,
index: number
@@ -43,7 +43,7 @@ const useColumnResizing = (
tablePersistentSettingsKey?: string
): ColumnResizingOutput => {
const tableContainerRef = useRef(null);
- const [columns, setColumns] = useState([]);
+ const [columns, setColumns] = useState(tableColumns);
const [isResizing, setIsResizing] = useState(false);
const columnsSizingRef = useRef<{ [key: string]: number }>({});
diff --git a/packages/design-system/src/components/table/useTable/useColumnResizing/resizeColumns.ts b/packages/design-system/src/components/table/useTable/useColumnResizing/resizeColumns.ts
index 9d7d0737d..34f8bf834 100644
--- a/packages/design-system/src/components/table/useTable/useColumnResizing/resizeColumns.ts
+++ b/packages/design-system/src/components/table/useTable/useColumnResizing/resizeColumns.ts
@@ -17,7 +17,7 @@
/**
* Internal dependencies
*/
-import { TableColumn } from '..';
+import { TableColumn } from '../types';
export const resizeColumns = (
columnsToResize: TableColumn[],
diff --git a/packages/design-system/src/components/table/useTable/useColumnSorting/index.tsx b/packages/design-system/src/components/table/useTable/useColumnSorting/index.tsx
index d6a44448e..8dea36fc1 100644
--- a/packages/design-system/src/components/table/useTable/useColumnSorting/index.tsx
+++ b/packages/design-system/src/components/table/useTable/useColumnSorting/index.tsx
@@ -23,7 +23,7 @@ import { getValueByKey } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import type { TableData } from '..';
+import type { TableData } from '../types';
import { useTablePersistentSettingsStore } from '../../persistentSettingsStore';
export type DefaultOptions = {
diff --git a/packages/design-system/src/components/table/useTable/useColumnVisibility/index.tsx b/packages/design-system/src/components/table/useTable/useColumnVisibility/index.tsx
index 5f65feff5..78b077088 100644
--- a/packages/design-system/src/components/table/useTable/useColumnVisibility/index.tsx
+++ b/packages/design-system/src/components/table/useTable/useColumnVisibility/index.tsx
@@ -22,7 +22,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
/**
* Internal dependencies.
*/
-import type { TableColumn } from '..';
+import type { TableColumn } from '../types';
import { useTablePersistentSettingsStore } from '../../persistentSettingsStore';
export type ColumnVisibilityOutput = {
@@ -100,12 +100,17 @@ const useColumnVisibility = (
[hiddenKeys]
);
- const visibleColumns = useMemo(() => {
+ const [visibleColumns, setVisibleColumns] = useState([]);
+
+ useEffect(() => {
if (isDataLoading) {
- return [];
+ setVisibleColumns([]);
+ return;
}
- return columns.filter(({ accessorKey }) => !hiddenKeys?.has(accessorKey));
+ setVisibleColumns(
+ columns.filter(({ accessorKey }) => !hiddenKeys?.has(accessorKey))
+ );
}, [columns, hiddenKeys, isDataLoading]);
const { getPreferences, setPreferences } = useTablePersistentSettingsStore(
diff --git a/packages/design-system/src/components/table/useTable/useFiltering/index.tsx b/packages/design-system/src/components/table/useTable/useFiltering/index.tsx
index ae919dcdb..afbc83d29 100644
--- a/packages/design-system/src/components/table/useTable/useFiltering/index.tsx
+++ b/packages/design-system/src/components/table/useTable/useFiltering/index.tsx
@@ -23,7 +23,7 @@ import { getValueByKey } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import type { TableData, TableFilter } from '..';
+import type { TableData, TableFilter } from '../types';
import useFiltersPersistence from './useFiltersPersistence';
export type TableFilteringOutput = {
@@ -65,6 +65,7 @@ const useFiltering = (
setIsDataLoading(true);
}, [specificTablePersistentSettingsKey]);
+ // extract filters from data
useEffect(() => {
setFilters((prevFilters) =>
Object.fromEntries(
@@ -116,6 +117,7 @@ const useFiltering = (
);
}, [data, selectAllFilterSelection]);
+ // extract filters from precalculated filter values
useEffect(() => {
const filtersByKey = Object.fromEntries(
Object.entries(tableFilterData || {})
@@ -148,14 +150,19 @@ const useFiltering = (
if (!filter.filterValues?.[_filterValue]) {
filterValues[_filterValue] = {
...filterValueData,
- selected: isSelectAllFilterSelected || false,
+ selected:
+ isSelectAllFilterSelected ||
+ filterValueData.selected ||
+ false,
};
} else {
filterValues[_filterValue] = {
...filterValueData,
selected:
isSelectAllFilterSelected ||
- filter.filterValues[_filterValue].selected,
+ filter.filterValues[_filterValue].selected ||
+ filterValueData.selected ||
+ false,
};
}
}
@@ -168,18 +175,22 @@ const useFiltering = (
});
}, [selectAllFilterSelection, tableFilterData]);
+ // extract filterKeys with selectAllFilter enabled
useEffect(() => {
const filtersWithSelectAllFilterEnabled = Object.entries(
tableFilterData || {}
)
.filter(([, filter]) => filter.enableSelectAllOption)
- .reduce>((acc, [filterKey]) => {
- acc[filterKey] = {
- selected: false,
- };
+ .reduce>(
+ (acc, [filterKey, filterValueData]) => {
+ acc[filterKey] = {
+ selected: filterValueData.isSelectAllOptionSelected || false,
+ };
- return acc;
- }, {});
+ return acc;
+ },
+ {}
+ );
setSelectAllFilterSelection((prev) => {
const newSelectAllFilterSelection = { ...prev };
@@ -187,7 +198,12 @@ const useFiltering = (
Object.entries(filtersWithSelectAllFilterEnabled).forEach(
([filterKey, filterValueData]) => {
if (!newSelectAllFilterSelection[filterKey]) {
- newSelectAllFilterSelection[filterKey] = filterValueData;
+ newSelectAllFilterSelection[filterKey] = {
+ selected:
+ newSelectAllFilterSelection[filterKey]?.selected ||
+ filterValueData.selected ||
+ false,
+ };
}
}
);
diff --git a/packages/design-system/src/components/table/useTable/useFiltering/useFiltersPersistence.tsx b/packages/design-system/src/components/table/useTable/useFiltering/useFiltersPersistence.tsx
index cde349c9d..b099268ba 100644
--- a/packages/design-system/src/components/table/useTable/useFiltering/useFiltersPersistence.tsx
+++ b/packages/design-system/src/components/table/useTable/useFiltering/useFiltersPersistence.tsx
@@ -18,8 +18,12 @@
* Internal dependencies.
*/
import { useCallback, useEffect, useMemo, useRef } from 'react';
+
+/**
+ * Internal dependencies.
+ */
import { useTablePersistentSettingsStore } from '../../persistentSettingsStore';
-import { PersistentStorageData, TableFilter } from '..';
+import { PersistentStorageData, TableFilter } from '../types';
const useFiltersPersistence = (
filters: TableFilter | undefined,
diff --git a/packages/design-system/src/components/table/useTable/useSearch/index.tsx b/packages/design-system/src/components/table/useTable/useSearch/index.tsx
index 08b10926c..df4b856cb 100644
--- a/packages/design-system/src/components/table/useTable/useSearch/index.tsx
+++ b/packages/design-system/src/components/table/useTable/useSearch/index.tsx
@@ -23,7 +23,7 @@ import { getValueByKey } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import { PersistentStorageData, TableData } from '..';
+import { PersistentStorageData, TableData } from '../types';
import { useTablePersistentSettingsStore } from '../../persistentSettingsStore';
export type TableSearchOutput = {
diff --git a/packages/design-system/src/components/table/useTable/useTable.tsx b/packages/design-system/src/components/table/useTable/useTable.tsx
new file mode 100644
index 000000000..a9c9a906f
--- /dev/null
+++ b/packages/design-system/src/components/table/useTable/useTable.tsx
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { useContextSelector } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import { TableContext, TableStoreContext } from './context';
+
+export function useTable(): TableStoreContext;
+export function useTable(selector: (state: TableStoreContext) => T): T;
+
+/**
+ * Table store hook.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useTable(
+ selector: (state: TableStoreContext) => T | TableStoreContext = (state) =>
+ state
+) {
+ return useContextSelector(TableContext, selector);
+}
diff --git a/packages/design-system/src/components/table/utils/generateCookieTableCSV.ts b/packages/design-system/src/components/table/utils/generateCookieTableCSV.ts
index 2731aed07..b44315226 100644
--- a/packages/design-system/src/components/table/utils/generateCookieTableCSV.ts
+++ b/packages/design-system/src/components/table/utils/generateCookieTableCSV.ts
@@ -13,11 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
/**
- * Internal dependencies.
+ * External dependencies.
*/
-import { CookieTableData, sanitizeCsvRecord } from '@ps-analysis-tool/common';
+import {
+ BLOCK_STATUS,
+ CookieTableData,
+ sanitizeCsvRecord,
+} from '@ps-analysis-tool/common';
const COOKIES_TABLE_DATA_HEADER = [
'Name',
@@ -32,16 +35,30 @@ const COOKIES_TABLE_DATA_HEADER = [
'Value',
'Path',
'Expires',
- 'Cookie Affected',
+ 'Issues',
'GDPRPortal',
'Priority',
'Size',
+ 'Blocking Status',
];
const generateCookieTableCSV = (cookies: CookieTableData[]): Blob => {
let cookieRecords = '';
for (const cookie of cookies) {
+ const isInboundBlocked =
+ cookie.blockingStatus?.inboundBlock !== BLOCK_STATUS.NOT_BLOCKED;
+ const isOutboundBlocked =
+ cookie.blockingStatus?.outboundBlock !== BLOCK_STATUS.NOT_BLOCKED;
+ const hasValidBlockedReason =
+ cookie?.blockedReasons && cookie.blockedReasons.length !== 0;
+
+ let status = '';
+
+ if ((isInboundBlocked || isOutboundBlocked) && !hasValidBlockedReason) {
+ status = 'Undetermined';
+ }
+
//This should be in the same order as cookieDataHeader
const recordsArray = [
cookie.parsedCookie.name,
@@ -60,6 +77,7 @@ const generateCookieTableCSV = (cookies: CookieTableData[]): Blob => {
cookie.analytics?.gdprUrl || 'NA',
cookie.parsedCookie.priority || ' ',
cookie.parsedCookie.size?.toString(),
+ status,
].map(sanitizeCsvRecord);
cookieRecords += recordsArray.join(',') + '\r\n';
diff --git a/packages/design-system/src/components/table/utils/index.ts b/packages/design-system/src/components/table/utils/index.ts
index ca26ee7c5..2dfe9fc89 100644
--- a/packages/design-system/src/components/table/utils/index.ts
+++ b/packages/design-system/src/components/table/utils/index.ts
@@ -15,3 +15,4 @@
*/
export { default as generateCookieTableCSV } from './generateCookieTableCSV';
+export * from './precalculatedFiltersUtils';
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateBlockedReasonsFilterValues.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateBlockedReasonsFilterValues.ts
new file mode 100644
index 000000000..b4b622fd6
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateBlockedReasonsFilterValues.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import { getValueByKey, type CookieTableData } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies
+ */
+import { TableFilter } from '../../useTable';
+
+/**
+ * Calculate the filter values for the blocked reasons filter.
+ * Use options to preselect the filter values.
+ * @param tabCookies Cookies to calculate the filter values from.
+ * @param options Options to preselect the filter values.
+ * @param clearQuery Function to clear the query(when options are provided) to avoid conflicts.
+ * @returns Filter values for the blocked reasons filter.
+ */
+const calculateBlockedReasonsFilterValues = (
+ tabCookies: CookieTableData[],
+ options: string[],
+ clearQuery?: () => void
+) => {
+ const filters = tabCookies.reduce<
+ TableFilter[keyof TableFilter]['filterValues']
+ >((acc, cookie) => {
+ const blockedReason = getValueByKey('blockedReasons', cookie);
+
+ if (!cookie.frameIdList) {
+ return acc;
+ }
+
+ blockedReason?.forEach((reason: string) => {
+ if (!acc) {
+ acc = {};
+ }
+
+ if (!acc[reason]) {
+ acc[reason] = {
+ selected: false,
+ };
+
+ if (options) {
+ acc[reason].selected = options.includes(reason);
+ }
+ }
+ });
+
+ return acc;
+ }, {});
+
+ if (options) {
+ clearQuery?.();
+ }
+
+ return filters;
+};
+
+export default calculateBlockedReasonsFilterValues;
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateDynamicFilterValues.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateDynamicFilterValues.ts
new file mode 100644
index 000000000..7eee03c29
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateDynamicFilterValues.ts
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import { getValueByKey, type CookieTableData } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies
+ */
+import { TableFilter } from '../../useTable';
+
+/**
+ * Calculate the filter values for the provider key.
+ * Use options to preselect the filter values, if options are provided clear the query to avoid conflicts.
+ * @param key Key to calculate the filter values for.
+ * @param tabCookies Cookies to calculate the filter values from.
+ * @param options Options to preselect the filter values.
+ * @param clearQuery Function to clear the query(when options are provided) to avoid conflicts.
+ * @returns Filters for the provider key.
+ */
+const calculateDynamicFilterValues = (
+ key: string,
+ tabCookies: CookieTableData[],
+ options: string[],
+ clearQuery?: () => void
+): TableFilter[keyof TableFilter]['filterValues'] => {
+ const filters = tabCookies.reduce<
+ TableFilter[keyof TableFilter]['filterValues']
+ >((acc, cookie) => {
+ const value = getValueByKey(key, cookie);
+
+ if (!acc) {
+ acc = {};
+ }
+
+ if (value && !acc[value]) {
+ acc[value] = {
+ selected: false,
+ };
+
+ if (options) {
+ acc[value].selected = options.includes(value);
+ }
+ }
+
+ return acc;
+ }, {});
+
+ if (options) {
+ clearQuery?.();
+ }
+
+ return filters;
+};
+
+export default calculateDynamicFilterValues;
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateExemptionReasons.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateExemptionReasons.ts
new file mode 100644
index 000000000..254639cdd
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/calculateExemptionReasons.ts
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * External dependencies
+ */
+import { CookieTableData } from '@ps-analysis-tool/common';
+/*
+ * Internal dependencies
+ */
+import { TableFilter } from '../../useTable';
+
+/**
+ * This function will return set of non duplicated cookie execmption reason.
+ * @param cookies The cookie table data.
+ * @param clearQuery Function to clear the query(when options are provided) to avoid conflicts.
+ * @param options Options to preselect the filter values.
+ * @returns {string[]} Unique set of exemption reasons.
+ */
+function frameOnlyExemptionReasonValues(
+ cookies: CookieTableData[],
+ clearQuery?: () => void,
+ options?: string[]
+) {
+ const collectedExemptionReasons = Array.from(
+ new Set(
+ cookies.map(({ exemptionReason }) => {
+ if (!exemptionReason || exemptionReason.toLowerCase() === 'none') {
+ return null;
+ }
+ return exemptionReason;
+ })
+ )
+ );
+
+ const reasons = collectedExemptionReasons.reduce((acc, reason) => {
+ if (!acc) {
+ acc = {};
+ }
+
+ if (reason) {
+ acc[reason] = {
+ selected: false,
+ };
+
+ if (options) {
+ acc[reason].selected = options.includes(reason);
+ }
+ }
+
+ return acc;
+ }, {} as TableFilter[keyof TableFilter]['filterValues']);
+
+ if (options) {
+ clearQuery?.();
+ }
+
+ return reasons;
+}
+
+export default frameOnlyExemptionReasonValues;
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/evaluateSelectAllOption.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/evaluateSelectAllOption.ts
new file mode 100644
index 000000000..d52ddc71e
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/evaluateSelectAllOption.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Evaluate if the 'All' option is present in parsedQuery.
+ * @param filterKey Filter key to evaluate.
+ * @param parsedQuery Query to evaluate from.
+ * @param clearActivePanelQuery Function to clear the query to avoid conflicts.
+ * @returns True if 'All' option is present in parsedQuery, false otherwise.
+ */
+const evaluateSelectAllOption = (
+ filterKey: string,
+ parsedQuery: Record,
+ clearActivePanelQuery?: () => void
+) => {
+ const options: string[] = parsedQuery?.filter?.[filterKey];
+
+ if (options?.[0] === 'All') {
+ clearActivePanelQuery?.();
+
+ return true;
+ }
+
+ return false;
+};
+
+export default evaluateSelectAllOption;
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/evaluateStaticFilterValues.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/evaluateStaticFilterValues.ts
new file mode 100644
index 000000000..ee25f1d2d
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/evaluateStaticFilterValues.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { TableFilter } from '../../useTable';
+
+/**
+ * Preselect the static filter values based on the options provided.
+ * @param staticValues Filter values to evaluate.
+ * @param filterKey Filter key to evaluate.
+ * @param parsedQuery Query to evaluate from.
+ * @param clearActivePanelQuery Function to clear the query to avoid conflicts.
+ * @returns Filter values for the static filter.
+ */
+const evaluateStaticFilterValues = (
+ staticValues: TableFilter[keyof TableFilter]['filterValues'],
+ filterKey: string,
+ parsedQuery: Record,
+ clearActivePanelQuery?: () => void
+) => {
+ const options: string[] = parsedQuery?.filter?.[filterKey];
+
+ if (!options) {
+ return staticValues;
+ }
+
+ const filters = Object.entries(staticValues || {}).reduce(
+ (acc, [key, value]) => {
+ if (!acc) {
+ acc = {};
+ }
+
+ if (options) {
+ value.selected = options.includes(key);
+ }
+
+ acc[key] = value;
+
+ return acc;
+ },
+ {} as TableFilter[keyof TableFilter]['filterValues']
+ );
+
+ if (options) {
+ clearActivePanelQuery?.();
+ }
+
+ return filters;
+};
+
+export default evaluateStaticFilterValues;
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/index.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/index.ts
new file mode 100644
index 000000000..dbd3d2ee3
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { default as calculateDynamicFilterValues } from './calculateDynamicFilterValues';
+export { default as evaluateStaticFilterValues } from './evaluateStaticFilterValues';
+export { default as evaluateSelectAllOption } from './evaluateSelectAllOption';
+export { default as calculateBlockedReasonsFilterValues } from './calculateBlockedReasonsFilterValues';
+export { default as calculateExemptionReason } from './calculateExemptionReasons';
diff --git a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/tests/calculateBlockedReasonsFilterValues.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateBlockedReasonsFilterValues.ts
similarity index 66%
rename from packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/tests/calculateBlockedReasonsFilterValues.ts
rename to packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateBlockedReasonsFilterValues.ts
index 477edc1d6..ffca3be68 100644
--- a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/tests/calculateBlockedReasonsFilterValues.ts
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateBlockedReasonsFilterValues.ts
@@ -44,9 +44,38 @@ describe('calculateBlockedReasonsFilterValues', () => {
selected: false,
},
};
+ const mockClearQuery = jest.fn();
- const result = calculateBlockedReasonsFilterValues(tabCookies);
+ const result = calculateBlockedReasonsFilterValues(
+ tabCookies,
+ undefined,
+ mockClearQuery
+ );
expect(result).toEqual(expected);
+ expect(mockClearQuery).not.toHaveBeenCalled();
+
+ const options = ['foo', 'bar'];
+
+ const expectedWithSelected = {
+ foo: {
+ selected: true,
+ },
+ bar: {
+ selected: true,
+ },
+ baz: {
+ selected: false,
+ },
+ };
+
+ const resultWithSelected = calculateBlockedReasonsFilterValues(
+ tabCookies,
+ options,
+ mockClearQuery
+ );
+
+ expect(resultWithSelected).toEqual(expectedWithSelected);
+ expect(mockClearQuery).toHaveBeenCalledTimes(1);
});
});
diff --git a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/tests/calculateDynamicFilterValues.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateDynamicFilterValues.ts
similarity index 62%
rename from packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/tests/calculateDynamicFilterValues.ts
rename to packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateDynamicFilterValues.ts
index c67f74b2d..749a428e6 100644
--- a/packages/cli-dashboard/src/hooks/useCookieListing.tsx/utils/tests/calculateDynamicFilterValues.ts
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateDynamicFilterValues.ts
@@ -43,10 +43,44 @@ describe('calculateDynamicFilterValues', () => {
},
};
+ const mockClearQuery = jest.fn();
+
// Act
- const result = calculateDynamicFilterValues('keyToExtract', tabCookies);
+ const result = calculateDynamicFilterValues(
+ 'keyToExtract',
+ tabCookies,
+ undefined,
+ mockClearQuery
+ );
// Assert
expect(result).toEqual(expected);
+ expect(mockClearQuery).not.toHaveBeenCalled();
+
+ const options = ['value1', 'value2'];
+
+ const expectedWithSelected = {
+ value1: {
+ selected: true,
+ },
+ value2: {
+ selected: true,
+ },
+ value3: {
+ selected: false,
+ },
+ };
+
+ // Act
+ const resultWithSelected = calculateDynamicFilterValues(
+ 'keyToExtract',
+ tabCookies,
+ options,
+ mockClearQuery
+ );
+
+ // Assert
+ expect(resultWithSelected).toEqual(expectedWithSelected);
+ expect(mockClearQuery).toHaveBeenCalledTimes(1);
});
});
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateExemptionReasons.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateExemptionReasons.ts
new file mode 100644
index 000000000..0042363a0
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/calculateExemptionReasons.ts
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import calculateExemptionReason from '../calculateExemptionReasons';
+
+describe('calculateExemptionReason', () => {
+ it('should no exemption reasons', () => {
+ const tabCookies = [
+ {
+ exemptionReason: 'None',
+ },
+ {
+ exemptionReason: 'None',
+ },
+ {
+ exemptionReason: 'None',
+ },
+ ];
+
+ const expected = {};
+
+ const clearActivePanelQuery = jest.fn();
+
+ const result = calculateExemptionReason(tabCookies, clearActivePanelQuery);
+
+ // Assert
+ expect(result).toStrictEqual(expected);
+ expect(clearActivePanelQuery).not.toHaveBeenCalled();
+ });
+
+ it('should return unique set of exemption reason.', () => {
+ const tabCookies = [
+ {
+ exemptionReason: 'UserSettings',
+ },
+ {
+ exemptionReason: 'TPCDHeuristics',
+ },
+ {
+ exemptionReason: 'None',
+ },
+ ];
+
+ const expected = {
+ UserSettings: {
+ selected: false,
+ },
+ TPCDHeuristics: {
+ selected: false,
+ },
+ };
+
+ const clearActivePanelQuery = jest.fn();
+
+ const result = calculateExemptionReason(tabCookies, clearActivePanelQuery);
+
+ // Assert
+ expect(result).toStrictEqual(expected);
+ expect(clearActivePanelQuery).not.toHaveBeenCalled();
+ });
+});
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/evaluateSelectAllOption.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/evaluateSelectAllOption.ts
new file mode 100644
index 000000000..056a07fda
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/evaluateSelectAllOption.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import evaluateSelectAllOption from '../evaluateSelectAllOption';
+
+describe('evaluateSelectAllOption', () => {
+ it('should return true if the first option is "All"', () => {
+ // Arrange
+ const filterKey = 'blockedReasons';
+ const parsedQuery = {
+ filter: {
+ blockedReasons: ['All'],
+ },
+ };
+ const clearActivePanelQuery = jest.fn();
+
+ const result = evaluateSelectAllOption(
+ filterKey,
+ undefined,
+ clearActivePanelQuery
+ );
+
+ // Assert
+ expect(result).toBe(false);
+ expect(clearActivePanelQuery).not.toHaveBeenCalled();
+
+ // Act
+ const result2 = evaluateSelectAllOption(
+ filterKey,
+ parsedQuery,
+ clearActivePanelQuery
+ );
+
+ // Assert
+ expect(result2).toBe(true);
+ expect(clearActivePanelQuery).toHaveBeenCalled();
+ });
+});
diff --git a/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/evaluateStaticFilterValues.ts b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/evaluateStaticFilterValues.ts
new file mode 100644
index 000000000..ae85f22c0
--- /dev/null
+++ b/packages/design-system/src/components/table/utils/precalculatedFiltersUtils/tests/evaluateStaticFilterValues.ts
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import evaluateStaticFilterValues from '../evaluateStaticFilterValues';
+
+describe('evaluateSelectAllOption', () => {
+ it('should return filter values based on the parsed query', () => {
+ // Arrange
+ const filterKey = 'isFioo';
+ const parsedQuery = {
+ filter: {
+ isFioo: ['Option1', 'Option2'],
+ },
+ };
+ const clearActivePanelQuery = jest.fn();
+ const staticValues = {
+ Option1: { selected: false },
+ Option2: { selected: false },
+ Option3: { selected: false },
+ };
+
+ // Arrange
+ const result1 = evaluateStaticFilterValues(
+ staticValues,
+ filterKey,
+ undefined,
+ clearActivePanelQuery
+ );
+
+ // Assert
+ expect(result1).toEqual({
+ Option1: { selected: false },
+ Option2: { selected: false },
+ Option3: { selected: false },
+ });
+ expect(clearActivePanelQuery).not.toHaveBeenCalled();
+
+ // Act
+ const result2 = evaluateStaticFilterValues(
+ staticValues,
+ filterKey,
+ parsedQuery,
+ clearActivePanelQuery
+ );
+
+ // Assert
+ expect(result2).toEqual({
+ Option1: { selected: true },
+ Option2: { selected: true },
+ Option3: { selected: false },
+ });
+ expect(clearActivePanelQuery).toHaveBeenCalled();
+ });
+});
diff --git a/packages/design-system/src/components/toastMessage/index.tsx b/packages/design-system/src/components/toastMessage/index.tsx
index 012ec0a35..4ec5a89e0 100644
--- a/packages/design-system/src/components/toastMessage/index.tsx
+++ b/packages/design-system/src/components/toastMessage/index.tsx
@@ -16,7 +16,7 @@
/**
* External dependencies.
*/
-import React, { forwardRef } from 'react';
+import React from 'react';
/**
* Internal dependencies.
@@ -31,30 +31,24 @@ interface ToastMessageProps {
variant?: 'primary' | 'secondary' | 'danger' | 'small' | 'large';
buttonText?: string;
}
-const ToastMessage = forwardRef(
- function ToastMessage(
- {
- text,
- onClick,
- additionalStyles = '',
- textAdditionalStyles = '',
- variant = 'large',
- buttonText = 'Reload',
- }: ToastMessageProps,
- ref
- ) {
- return (
-
-
+const ToastMessage = ({
+ text,
+ onClick,
+ additionalStyles = '',
+ textAdditionalStyles = '',
+ variant = 'large',
+ buttonText = 'Reload',
+}: ToastMessageProps) => {
+ return (
+
+ );
+};
export default ToastMessage;
diff --git a/packages/design-system/src/components/toggleSwitch/index.tsx b/packages/design-system/src/components/toggleSwitch/index.tsx
index 96e36a1fb..159046b2d 100644
--- a/packages/design-system/src/components/toggleSwitch/index.tsx
+++ b/packages/design-system/src/components/toggleSwitch/index.tsx
@@ -38,6 +38,7 @@ const ToggleSwitch = ({
<>
setEnabled(!enabled)}
/>
+
+
diff --git a/packages/design-system/src/icons/index.tsx b/packages/design-system/src/icons/index.tsx
index 1681d1dde..abd1de927 100644
--- a/packages/design-system/src/icons/index.tsx
+++ b/packages/design-system/src/icons/index.tsx
@@ -69,3 +69,5 @@ export { default as OutboundInboundIcon } from './outbound-inbound-icon.svg';
export { default as OutboundInboundColoredIcon } from './outbound-inbound-colored-icon.svg';
export { default as QuestionMark } from './question-mark.svg';
export { default as GreenTick } from './green-tick-icon.svg';
+export { default as ChevronDown } from './chevron-down.svg';
+export { default as WarningBare } from './warning.svg';
diff --git a/packages/design-system/src/icons/warning.svg b/packages/design-system/src/icons/warning.svg
new file mode 100644
index 000000000..18fa65b44
--- /dev/null
+++ b/packages/design-system/src/icons/warning.svg
@@ -0,0 +1,2 @@
+
+
diff --git a/packages/design-system/src/test-data/cookieStats.ts b/packages/design-system/src/test-data/cookieStats.ts
index de50c11fe..15c6589ec 100644
--- a/packages/design-system/src/test-data/cookieStats.ts
+++ b/packages/design-system/src/test-data/cookieStats.ts
@@ -14,16 +14,16 @@
* limitations under the License.
*/
export default {
- total: 7,
+ total: 1000,
blockedCookies: {
total: 0,
},
firstParty: {
- total: 6,
+ total: 999,
functional: 0,
marketing: 0,
analytics: 2,
- uncategorized: 4,
+ uncategorized: 998,
},
thirdParty: {
total: 1,
diff --git a/packages/design-system/src/test-data/cookieTableMockData.tsx b/packages/design-system/src/test-data/cookieTableMockData.tsx
index 143de80f6..38cad920e 100644
--- a/packages/design-system/src/test-data/cookieTableMockData.tsx
+++ b/packages/design-system/src/test-data/cookieTableMockData.tsx
@@ -90,82 +90,82 @@ export const rows = [
{
// @ts-ignore
'parsedCookie.name': {
- value: 'guest_id',
+ value: () => 'guest_id',
},
'parsedCookie.value': {
- value: 'v1%3A169761712418716012',
+ value: () => 'v1%3A169761712418716012',
},
'parsedCookie.domain': {
- value: '.twitter.com',
+ value: () => '.twitter.com',
},
'parsedCookie.path': {
- value: '/',
+ value: () => '/',
},
'parsedCookie.expires': {
- value: '2024-11-21T08:18:44.337Z',
+ value: () => '2024-11-21T08:18:44.337Z',
},
'parsedCookie.httponly': {
- value: ✓ ,
+ value: () => ✓ ,
},
'parsedCookie.samesite': {
- value: ,
+ value: () => ,
},
'parsedCookie.secure': {
- value: (
+ value: () => (
✓
),
},
'analytics.category': {
- value: 'Marketing',
+ value: () => 'Marketing',
},
'analytics.platform': {
- value: 'Twitter',
+ value: () => 'Twitter',
},
isFirstParty: {
- value: 'Third Party',
+ value: () => 'Third Party',
},
originalData: originalData[0],
},
{
// @ts-ignore
'parsedCookie.name': {
- value: 'personalization_id',
+ value: () => 'personalization_id',
},
'parsedCookie.value': {
- value: 'v1_HJmmucUuUZDLmLGgaw/32w==',
+ value: () => 'v1_HJmmucUuUZDLmLGgaw/32w==',
},
'parsedCookie.domain': {
- value: '.twitter.com',
+ value: () => '.twitter.com',
},
'parsedCookie.path': {
- value: '/',
+ value: () => '/',
},
'parsedCookie.expires': {
- value: '2024-11-21T08:18:44.337Z',
+ value: () => '2024-11-21T08:18:44.337Z',
},
'parsedCookie.httponly': {
- value: ✓ ,
+ value: () => ✓ ,
},
'parsedCookie.samesite': {
- value: ,
+ value: () => ,
},
'parsedCookie.secure': {
- value: (
+ value: () => (
✓
),
},
'analytics.category': {
- value: 'Marketing',
+ value: () => 'Marketing',
},
'analytics.platform': {
- value: 'Twitter',
+ value: () => 'Twitter',
},
isFirstParty: {
- value: 'Third Party',
+ value: () => 'Third Party',
},
originalData: originalData[1],
},
diff --git a/packages/design-system/src/theme/colors.ts b/packages/design-system/src/theme/colors.ts
index 74ace5bb7..f38f13822 100644
--- a/packages/design-system/src/theme/colors.ts
+++ b/packages/design-system/src/theme/colors.ts
@@ -144,4 +144,47 @@ export const COLOR_MAP: {
color: '#D5CABD',
className: 'text-hotrod-brown',
},
+ None: {
+ color: '#465362',
+ className: 'text-color-charcoal',
+ },
+ UserSetting: {
+ color: '#F9DC5C',
+ className: 'text-napels-yellow',
+ },
+
+ TPCDMetadata: {
+ color: '#ED254E',
+ className: 'text-red-corolla',
+ },
+
+ TPCDDeprecationTrial: {
+ color: '#08A4BD',
+ className: 'text-moonstone',
+ },
+
+ TPCDHeuristics: {
+ color: '#446DF6',
+ className: 'text-noon-blue',
+ },
+
+ EnterprisePolicy: {
+ color: '#4C212A',
+ className: 'text-chocolate-cosmos',
+ },
+
+ StorageAccess: {
+ color: '#D96C06',
+ className: 'text-cocoa-brown',
+ },
+
+ TopLevelStorageAccess: {
+ color: '#3A1772',
+ className: 'text-persian-indigo',
+ },
+
+ CorsOptIn: {
+ color: '#D741A7',
+ className: 'text-hollywood-cerise',
+ },
};
diff --git a/packages/design-system/src/utils/index.ts b/packages/design-system/src/utils/index.ts
index f25ad60c6..098e4a669 100644
--- a/packages/design-system/src/utils/index.ts
+++ b/packages/design-system/src/utils/index.ts
@@ -18,3 +18,4 @@ export { noop } from './noop';
export { default as prepareCookiesCount } from './prepareCookiesCount';
export { default as prepareCookieStatsComponents } from './prepareCookieStatsComponents';
export { default as prepareFrameStatsComponent } from './prepareFrameStatsComponent';
+export { default as prepareCookieDataMapping } from './prepareCookieDataMapping';
diff --git a/packages/design-system/src/utils/prepareCookieDataMapping.ts b/packages/design-system/src/utils/prepareCookieDataMapping.ts
new file mode 100644
index 000000000..82a66290a
--- /dev/null
+++ b/packages/design-system/src/utils/prepareCookieDataMapping.ts
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import type {
+ CookieStatsComponents,
+ CookiesCount,
+} from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies
+ */
+import { DataMapping } from '../components/cookiesLanding/landingHeader';
+
+/**
+ * Calcualte insights about frames to be shown on cookies landing page.
+ * @param {CookiesCount} cookieStats The calculated cookie count for each type.
+ * @param {CookieStatsComponents} cookiesStatsComponents cookies statistics of curent tab with the legend data.
+ * @param selectedItemUpdater The function to update the selected item.
+ * @returns {DataMapping[]} Mapped data array for displaying the landing header.
+ */
+export default function prepareCookieDataMapping(
+ cookieStats: CookiesCount,
+ cookiesStatsComponents: CookieStatsComponents,
+ selectedItemUpdater: (title: string, accessorKey?: string) => void
+): DataMapping[] {
+ return [
+ {
+ title: 'Total cookies',
+ count: cookieStats.total,
+ data: cookiesStatsComponents.legend,
+ onClick: () => selectedItemUpdater('', 'isFirstParty'), // title is empty as we don't want to select any filter.
+ },
+ {
+ title: '1st party cookies',
+ count: cookieStats.firstParty.total,
+ data: cookiesStatsComponents.firstParty,
+ onClick: () => selectedItemUpdater('First Party', 'isFirstParty'),
+ },
+ {
+ title: '3rd party cookies',
+ count: cookieStats.thirdParty.total,
+ data: cookiesStatsComponents.thirdParty,
+ onClick: () => selectedItemUpdater('Third Party', 'isFirstParty'),
+ },
+ ];
+}
diff --git a/packages/design-system/src/utils/prepareCookieStatsComponents.ts b/packages/design-system/src/utils/prepareCookieStatsComponents.ts
index b9d735e7b..61ce8ecd9 100644
--- a/packages/design-system/src/utils/prepareCookieStatsComponents.ts
+++ b/packages/design-system/src/utils/prepareCookieStatsComponents.ts
@@ -33,11 +33,19 @@ const prepareCookieStatsComponents = (
const blockedCookiesLegend: CookieStatsComponents['blockedCookiesLegend'] =
[];
+ const exemptedCookiesStats: CookieStatsComponents['exempted'] = [];
+ const exemptedCookiesLegend: CookieStatsComponents['exemptedCookiesLegend'] =
+ [];
+
Object.keys(cookieStats.blockedCookies).forEach((key: string) => {
if (key === 'total') {
return;
}
+ if (isNaN(cookieStats.blockedCookies[key])) {
+ return;
+ }
+
blockedCookiesStats.push({
count: cookieStats.blockedCookies[key],
color: COLOR_MAP[key].color,
@@ -51,6 +59,27 @@ const prepareCookieStatsComponents = (
});
});
+ Object.keys(cookieStats.exemptedCookies).forEach((key: string) => {
+ if (key === 'total' || key.toLowerCase() === 'none') {
+ return;
+ }
+ if (isNaN(cookieStats.exemptedCookies[key])) {
+ return;
+ }
+
+ exemptedCookiesStats.push({
+ count: cookieStats.exemptedCookies[key],
+ color: COLOR_MAP[key].color,
+ });
+
+ exemptedCookiesLegend.push({
+ label: key,
+ count: cookieStats.exemptedCookies[key],
+ color: COLOR_MAP[key].color,
+ countClassName: COLOR_MAP[key].className,
+ });
+ });
+
return {
legend: [
{
@@ -121,6 +150,8 @@ const prepareCookieStatsComponents = (
],
blocked: blockedCookiesStats,
blockedCookiesLegend,
+ exempted: exemptedCookiesStats,
+ exemptedCookiesLegend,
};
};
diff --git a/packages/design-system/src/utils/prepareCookiesCount.ts b/packages/design-system/src/utils/prepareCookiesCount.ts
index 49d821fd2..41c1b57f3 100644
--- a/packages/design-system/src/utils/prepareCookiesCount.ts
+++ b/packages/design-system/src/utils/prepareCookiesCount.ts
@@ -30,6 +30,9 @@ const prepareCookiesCount = (cookies: { [key: string]: CookieData } | null) => {
blockedCookies: {
total: 0,
},
+ exemptedCookies: {
+ total: 0,
+ },
firstParty: {
total: 0,
functional: 0,
@@ -78,6 +81,26 @@ const prepareCookiesCount = (cookies: { [key: string]: CookieData } | null) => {
}
});
+ cookiesCount.exemptedCookies.total = cookieList.filter(
+ (cookie) =>
+ cookie.exemptionReason &&
+ cookie.exemptionReason.toLowerCase() !== 'none' &&
+ (cookie?.frameIdList ?? [])?.length >= 0
+ ).length;
+
+ cookieList.forEach((cookie) => {
+ if (
+ cookie.exemptionReason &&
+ cookie.exemptionReason.toLowerCase() !== 'none'
+ ) {
+ if (!cookiesCount.exemptedCookies[cookie.exemptionReason]) {
+ cookiesCount.exemptedCookies[cookie.exemptionReason] = 1;
+ } else {
+ cookiesCount.exemptedCookies[cookie.exemptionReason]++;
+ }
+ }
+ });
+
for (const cookie of cookieList) {
const { analytics, isFirstParty } = cookie;
const category = analytics?.category?.toLowerCase() as
diff --git a/packages/design-system/src/utils/tests/prepareCookiesCount.ts b/packages/design-system/src/utils/tests/prepareCookiesCount.ts
index b1ef6bd1b..7e04c0725 100644
--- a/packages/design-system/src/utils/tests/prepareCookiesCount.ts
+++ b/packages/design-system/src/utils/tests/prepareCookiesCount.ts
@@ -140,6 +140,9 @@ const EMPTY_STATS = {
blockedCookies: {
total: 0,
},
+ exemptedCookies: {
+ total: 0,
+ },
firstParty: {
total: 0,
functional: 0,
@@ -182,6 +185,9 @@ describe('prepareCookiesCount : ', () => {
blockedCookies: {
total: 0,
},
+ exemptedCookies: {
+ total: 0,
+ },
firstParty: {
total: 4,
functional: 1,
diff --git a/packages/eslint-import-resolver/package.json b/packages/eslint-import-resolver/package.json
index 399c8bd81..e1e881905 100644
--- a/packages/eslint-import-resolver/package.json
+++ b/packages/eslint-import-resolver/package.json
@@ -1,6 +1,6 @@
{
"name": "@ps-analysis-tool/eslint-import-resolver",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "",
"main": "src/index.cjs",
"scripts": {
diff --git a/packages/extension/icons/icon-12.png b/packages/extension/icons/icon-12.png
index 5dd1eac60..3f0169345 100644
Binary files a/packages/extension/icons/icon-12.png and b/packages/extension/icons/icon-12.png differ
diff --git a/packages/extension/icons/icon-128.png b/packages/extension/icons/icon-128.png
index b6e84290a..b4db39fd9 100644
Binary files a/packages/extension/icons/icon-128.png and b/packages/extension/icons/icon-128.png differ
diff --git a/packages/extension/icons/icon-16.png b/packages/extension/icons/icon-16.png
index f6b6b7604..c1cb4a47d 100644
Binary files a/packages/extension/icons/icon-16.png and b/packages/extension/icons/icon-16.png differ
diff --git a/packages/extension/icons/icon-32.png b/packages/extension/icons/icon-32.png
index b3039d557..481665f6c 100644
Binary files a/packages/extension/icons/icon-32.png and b/packages/extension/icons/icon-32.png differ
diff --git a/packages/extension/icons/icon-48.png b/packages/extension/icons/icon-48.png
index 9e2cbdbfe..74153ea99 100644
Binary files a/packages/extension/icons/icon-48.png and b/packages/extension/icons/icon-48.png differ
diff --git a/packages/extension/icons/icon.png b/packages/extension/icons/icon.png
deleted file mode 100644
index b6e84290a..000000000
Binary files a/packages/extension/icons/icon.png and /dev/null differ
diff --git a/packages/extension/icons/icon.svg b/packages/extension/icons/icon.svg
index c5820bd24..52a3c540d 100644
--- a/packages/extension/icons/icon.svg
+++ b/packages/extension/icons/icon.svg
@@ -1,82 +1,20 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/extension/package.json b/packages/extension/package.json
index 31142be3a..cf9d2448d 100644
--- a/packages/extension/package.json
+++ b/packages/extension/package.json
@@ -1,6 +1,6 @@
{
"name": "@ps-analysis-tool/extension",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "Chrome extension for cookie analysis",
"repository": {
"type": "git",
@@ -40,6 +40,7 @@
},
"devDependencies": {
"@types/react-copy-to-clipboard": "^5.0.4",
- "devtools-protocol": "^0.0.1236148"
+ "devtools-protocol": "^0.0.1282316",
+ "html-inline-script-webpack-plugin": "^3.2.1"
}
}
diff --git a/packages/extension/src/constants.ts b/packages/extension/src/constants.ts
index b146b4317..6790231fc 100644
--- a/packages/extension/src/constants.ts
+++ b/packages/extension/src/constants.ts
@@ -31,3 +31,19 @@ export const SETTING_PAGE_CONTROLS = [
"The PSAT tool is designed for efficient single-tab analysis. While multi-tab debugging is available for more comprehensive analysis, it is intended for examining 2-3 tabs simultaneously. Using more tabs may impact the tool's responsiveness.",
},
];
+
+export const DEVTOOLS_CLOSE = 'DEVTOOLS_STATE_CLOSE';
+export const DEVTOOLS_OPEN = 'DEVTOOLS_STATE_OPEN';
+export const POPUP_CLOSE = 'POPUP_STATE_CLOSE';
+export const POPUP_OPEN = 'POPUP_STATE_OPEN';
+export const DEVTOOLS_SET_JAVASCSCRIPT_COOKIE =
+ 'DevTools::SET_JAVASCRIPT_COOKIE';
+export const CHANGE_CDP_SETTING = 'CHANGE_CDP_SETTING';
+export const SET_TAB_TO_READ = 'SET_TAB_TO_READ';
+export const INITIAL_SYNC = 'INITIAL_SYNC';
+export const NEW_COOKIE_DATA = 'NEW_COOKIE_DATA';
+export const SERVICE_WORKER_RELOAD_MESSAGE = 'ServiceWorker::TABS_RELOADED';
+export const SERVICE_WORKER_TABS_RELOAD_COMMAND =
+ 'ServiceWorker::REOLAD_ALL_TABS';
+export const GET_JS_COOKIES = 'DEVTOOL::WEBPAGE::GET_JS_COOKIES';
+export const TABID_STORAGE = 'SERVICEWORKER::WEBPAGE::TABID_STORAGE';
diff --git a/packages/extension/src/contentScript/index.ts b/packages/extension/src/contentScript/index.ts
index 6832075cb..55f5e6e2b 100644
--- a/packages/extension/src/contentScript/index.ts
+++ b/packages/extension/src/contentScript/index.ts
@@ -38,7 +38,12 @@ import {
} from './popovers';
import type { ResponseType } from './types';
import { TOOLTIP_CLASS } from './constants';
-import { WEBPAGE_PORT_NAME } from '../constants';
+import {
+ DEVTOOLS_SET_JAVASCSCRIPT_COOKIE,
+ GET_JS_COOKIES,
+ TABID_STORAGE,
+ WEBPAGE_PORT_NAME,
+} from '../constants';
import {
isElementVisibleInViewport,
getFrameCount,
@@ -139,16 +144,18 @@ class WebpageContentScript {
await this.getAndProcessJSCookies(message.tabId);
}
- if (message?.payload?.type === 'SERVICEWORKER::WEBPAGE::TABID_STORAGE') {
+ if (message?.payload?.type === TABID_STORAGE) {
this.tabId = message.payload.tabId;
}
- if (message?.payload?.type === 'DEVTOOL::WEBPAGE::GET_JS_COOKIES') {
+ if (message?.payload?.type === GET_JS_COOKIES) {
await this.getAndProcessJSCookies(message.payload.tabId);
}
});
- this.cookieDB = await fetchDictionary();
+ if (!this.cookieDB) {
+ this.cookieDB = await fetchDictionary();
+ }
chrome.runtime.onConnect.addListener((port) => {
if (port.name.startsWith(WEBPAGE_PORT_NAME)) {
@@ -164,13 +171,17 @@ class WebpageContentScript {
* @param tabId The tabID whose cookies have to be fetched.
*/
async getAndProcessJSCookies(tabId: string) {
- //@ts-ignore
- const jsCookies = await cookieStore.getAll();
- await processAndStoreDocumentCookies({
- tabUrl: window.location.href,
- tabId,
- documentCookies: jsCookies,
- });
+ try {
+ //@ts-ignore
+ const jsCookies = await cookieStore.getAll();
+ await processAndStoreDocumentCookies({
+ tabUrl: window.location.href,
+ tabId,
+ documentCookies: jsCookies,
+ });
+ } catch (error) {
+ //Fail silently. No logging because sometimes cookieStore.getAll fails to run in some context.
+ }
}
/**
@@ -261,7 +272,7 @@ class WebpageContentScript {
}
chrome.runtime.sendMessage({
- type: 'DevTools::ServiceWorker::SET_JAVASCRIPT_COOKIE',
+ type: DEVTOOLS_SET_JAVASCSCRIPT_COOKIE,
payload: {
tabId: this.tabId,
cookieData: jsCookies,
diff --git a/packages/extension/src/contentScript/popovers/overlay/tests/addOverlay.ts b/packages/extension/src/contentScript/popovers/overlay/tests/addOverlay.ts
new file mode 100644
index 000000000..ceb90d83d
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/overlay/tests/addOverlay.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import addOverlay from '../addOverlay';
+
+describe('addOverlay', () => {
+ beforeAll(() => {
+ // Mock showPopover since it is not supported.
+ globalThis.HTMLElement.prototype.showPopover = jest.fn();
+ });
+
+ it('should return overlay that was added to the document body', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(
+ () =>
+ ({
+ height: 10,
+ width: 200,
+ } as DOMRect)
+ );
+
+ document.body.appendChild(iframe);
+
+ const overlay = addOverlay(iframe);
+
+ expect(overlay).toBeInTheDocument();
+ expect(overlay instanceof HTMLDivElement).toBe(true);
+ });
+
+ it('should return null as body not found', () => {
+ const iframe = document.createElement('iframe');
+ const overlay = addOverlay(iframe);
+
+ expect(overlay).toBe(null);
+ });
+
+ afterAll(() => {
+ globalThis.HTMLElement.prototype.showPopover =
+ undefined as unknown as typeof HTMLElement.prototype.showPopover;
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/overlay/tests/createFrameOverlay.ts b/packages/extension/src/contentScript/popovers/overlay/tests/createFrameOverlay.ts
new file mode 100644
index 000000000..9239b7703
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/overlay/tests/createFrameOverlay.ts
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import { OVERLAY_CLASS } from '../../../constants';
+import createFrameOverlay from '../createFrameOverlay';
+
+const mockGetBoundingClientRect = (height: number, width: number) => {
+ return {
+ height,
+ width,
+ } as DOMRect;
+};
+
+describe('createFrameOverlay', () => {
+ beforeAll(() => {
+ // Mock showPopover since it is not supported.
+ globalThis.HTMLElement.prototype.showPopover = jest.fn();
+ });
+
+ it('should return an overlay', () => {
+ const frame = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ frame.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(100, 100)
+ );
+
+ // Create overlay.
+ const overlay = createFrameOverlay(frame);
+
+ expect(overlay?.popover).toBe('manual');
+ expect(overlay).toHaveClass(OVERLAY_CLASS);
+ expect(overlay instanceof HTMLDivElement).toBe(true);
+ });
+
+ it('should return an overlay with dimension same as frame', () => {
+ const frame = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ frame.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(50, 50)
+ );
+
+ // Create overlay.
+ const overlay = createFrameOverlay(frame);
+
+ expect(overlay?.style.width).toBe('50px');
+ expect(overlay?.style.height).toBe('50px');
+ });
+
+ it('should return an overlay with "ps-fixed" class', () => {
+ const frame = document.createElement('body');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ frame.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(100, 100)
+ );
+
+ // Create overlay.
+ const overlay = createFrameOverlay(frame);
+
+ expect(overlay).toHaveClass('ps-fixed');
+ });
+
+ it('should return null if frame is hidden', () => {
+ const frameOne = document.createElement('iframe');
+ const frameTwo = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ frameOne.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(0, 100)
+ );
+
+ // Create overlay.
+ const overlayOne = createFrameOverlay(frameOne);
+
+ // Mock getBoundingClientRect since it always returns 0.
+ frameTwo.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(0, 100)
+ );
+
+ // Create overlay.
+ const overlayTwo = createFrameOverlay(frameTwo);
+
+ expect(overlayOne).toBe(null);
+ expect(overlayTwo).toBe(null);
+ });
+
+ afterAll(() => {
+ globalThis.HTMLElement.prototype.showPopover =
+ undefined as unknown as typeof HTMLElement.prototype.showPopover;
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/overlay/tests/setOverlayPosition.ts b/packages/extension/src/contentScript/popovers/overlay/tests/setOverlayPosition.ts
new file mode 100644
index 000000000..64f266b3b
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/overlay/tests/setOverlayPosition.ts
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import setOverlayPosition from '../setOverlayPosition';
+import addOverlay from '../addOverlay';
+
+const mockGetBoundingClientRect = (
+ x: number,
+ y: number,
+ height: number,
+ width: number
+) => {
+ return {
+ x,
+ y,
+ height,
+ width,
+ } as DOMRect;
+};
+
+describe('setOverlayPosition', () => {
+ beforeAll(() => {
+ // Mock showPopover since it is not supported.
+ globalThis.HTMLElement.prototype.showPopover = jest.fn();
+ });
+
+ it('should set overlay postion: Test 1', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(0, 0, 50, 50)
+ );
+
+ const overlay = addOverlay(iframe);
+
+ // Set overlay position.
+ setOverlayPosition(overlay, iframe);
+
+ expect(overlay?.style.top).toBe('0px');
+ expect(overlay?.style.left).toBe('0px');
+ });
+
+ it('should set overlay postion: Test 2', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(10, 20, 30, 20)
+ );
+
+ const overlay = addOverlay(iframe);
+
+ // Set overlay position.
+ setOverlayPosition(overlay, iframe);
+
+ expect(overlay?.style.top).toBe('20px');
+ expect(overlay?.style.left).toBe('10px');
+ });
+
+ it('should not set overlay postion if no overlay', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(10, 20, 0, 0)
+ );
+
+ const overlay = addOverlay(iframe);
+
+ // Set overlay position.
+ setOverlayPosition(overlay, iframe);
+
+ expect(overlay?.style.top).toBe(undefined);
+ expect(overlay?.style.left).toBe(undefined);
+ });
+
+ afterAll(() => {
+ globalThis.HTMLElement.prototype.showPopover =
+ undefined as unknown as typeof HTMLElement.prototype.showPopover;
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/tests/findSelectedFrameElements.ts b/packages/extension/src/contentScript/popovers/tests/findSelectedFrameElements.ts
new file mode 100644
index 000000000..027e7923f
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/tests/findSelectedFrameElements.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import findSelectedFrameElements from '../findSelectedFrameElements';
+
+describe('findSelectedFrameElements', () => {
+ it('should return empty array as origin is empty', () => {
+ const frame = findSelectedFrameElements('htts://example.com');
+
+ expect(frame).toHaveLength(0);
+ });
+
+ it('should return body frame as selectedOrigin is same as the origin', () => {
+ const origin = document.location.origin;
+ const frame = findSelectedFrameElements(origin);
+
+ expect(frame).toHaveLength(1);
+ expect(frame).toContain(document.body);
+ });
+
+ it('should return array of frames of same origin', () => {
+ const origin = 'https://example.com';
+
+ const iframeOne = document.createElement('iframe');
+ const iframeTwo = document.createElement('iframe');
+ const iframeThree = document.createElement('iframe');
+ const iframeFour = document.createElement('iframe');
+
+ iframeOne.setAttribute('src', 'https://example.com');
+ iframeTwo.setAttribute('src', 'https://server.com');
+ iframeThree.setAttribute('src', 'https://domain.com');
+ iframeFour.setAttribute('src', 'https://example.com');
+
+ const iframes = [iframeOne, iframeTwo, iframeThree, iframeFour];
+
+ iframes.forEach((iframe) => {
+ document.body.appendChild(iframe);
+ });
+
+ const frames = findSelectedFrameElements(origin);
+
+ expect(frames).toHaveLength(2);
+
+ frames.forEach((frame) => {
+ expect(frame.getAttribute('src')).toBe(origin);
+ });
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/tests/removeAllPopovers.ts b/packages/extension/src/contentScript/popovers/tests/removeAllPopovers.ts
new file mode 100644
index 000000000..a033d6751
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/tests/removeAllPopovers.ts
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import { OVERLAY_CLASS, TOOLTIP_CLASS } from '../../constants';
+import removeAllPopovers from '../removeAllPopovers';
+
+describe('removeAllPopovers', () => {
+ it('should remove all the popovers', () => {
+ const parentDiv = document.createElement('div');
+ const divEleArr = [];
+
+ for (let i = 0; i < 6; i++) {
+ const divEle = document.createElement('div');
+ divEleArr.push(divEle);
+ }
+
+ divEleArr.slice(0, 4).forEach((div) => {
+ div.classList.add(OVERLAY_CLASS);
+ parentDiv.appendChild(div);
+ });
+
+ divEleArr.slice(4, 6).forEach((div) => {
+ div.classList.add(TOOLTIP_CLASS);
+ parentDiv.appendChild(div);
+ });
+
+ document.body.appendChild(parentDiv);
+
+ // Get initial popovers count.
+ const overlaysBeforeRemoval = document.querySelectorAll(
+ `.${OVERLAY_CLASS}`
+ );
+ const tooltipsBeforeRemoval = document.querySelectorAll(
+ `.${TOOLTIP_CLASS}`
+ );
+
+ // Call the function to remove all popovers.
+ removeAllPopovers();
+
+ // Get popovers count after removing them.
+ const overlaysAfterRemoval = document.querySelectorAll(`.${OVERLAY_CLASS}`);
+ const tooltipsAfterRemoval = document.querySelectorAll(`.${TOOLTIP_CLASS}`);
+
+ expect(overlaysBeforeRemoval).toHaveLength(4);
+ expect(tooltipsBeforeRemoval).toHaveLength(2);
+
+ expect(overlaysAfterRemoval).toHaveLength(0);
+ expect(tooltipsAfterRemoval).toHaveLength(0);
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/tests/toggleFrameHighlighting.ts b/packages/extension/src/contentScript/popovers/tests/toggleFrameHighlighting.ts
new file mode 100644
index 000000000..370f4c35c
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/tests/toggleFrameHighlighting.ts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import toggleFrameHighlighting from '../toggleFrameHighlighting';
+
+describe('toggleFrameHighlighting', () => {
+ it('should add "ps-highlighted-frame" class for all iframes', () => {
+ const divWithIframes = document.createElement('div');
+
+ // Create div with iframes.
+ for (let i = 0; i < 10; i++) {
+ divWithIframes.appendChild(document.createElement('iframe'));
+ }
+
+ document.body.appendChild(divWithIframes);
+
+ toggleFrameHighlighting(true);
+
+ expect(
+ document.querySelectorAll('iframe.ps-highlighted-frame')
+ ).toHaveLength(10);
+ });
+
+ it('should remove "ps-highlighted-frame" class for all iframes', () => {
+ const divWithIframes = document.createElement('div');
+
+ // Create div with iframes.
+ for (let i = 0; i < 10; i++) {
+ divWithIframes.appendChild(document.createElement('iframe'));
+ }
+
+ document.body.appendChild(divWithIframes);
+
+ toggleFrameHighlighting(false);
+
+ expect(
+ document.querySelectorAll('iframe.ps-highlighted-frame')
+ ).toHaveLength(0);
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/tooltip/tests/createShowMoreButton.ts b/packages/extension/src/contentScript/popovers/tooltip/tests/createShowMoreButton.ts
new file mode 100644
index 000000000..0294bfb24
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/tooltip/tests/createShowMoreButton.ts
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import createShowMoreButton from '../createShowMoreButton';
+
+describe('createShowMoreButton', () => {
+ it('should contain "Show More" button components', () => {
+ // Get HTML element from the function being tested.
+ const tooltipShowButtonContainer = createShowMoreButton();
+ const tooltipShowButton = tooltipShowButtonContainer.children[0];
+
+ // Create additional content for the tooltip.
+ const tooltipContent = document.createElement('div');
+ tooltipContent.innerHTML = `
+
+ `;
+
+ // Create tooltip and append to the body element.
+ const tooltip = document.createElement('div');
+ tooltip.appendChild(tooltipContent);
+ tooltip.appendChild(tooltipShowButtonContainer);
+ document.body.appendChild(tooltip);
+
+ expect(tooltipShowButton instanceof HTMLButtonElement).toBe(true);
+ expect(tooltipShowButtonContainer instanceof HTMLDivElement).toBe(true);
+ expect((tooltipShowButton as HTMLElement).innerText).toBe('Show more');
+
+ expect(tooltipShowButton).toHaveClass('ps-tooltip-compact');
+ expect(tooltipShowButton).toHaveClass('ps-tooltip-info-toggle-btn');
+ });
+
+ it('button click should perform an action', () => {
+ // Get HTML element from the function being tested.
+ const tooltipShowButtonContainer = createShowMoreButton();
+ const tooltipShowButton = tooltipShowButtonContainer.children[0];
+
+ // Create additional content for the tooltip.
+ const tooltipContent = document.createElement('div');
+ tooltipContent.innerHTML = `
+
+ `;
+
+ // Create tooltip and append to the body element.
+ const tooltip = document.createElement('div');
+ tooltip.appendChild(tooltipContent);
+ tooltip.appendChild(tooltipShowButtonContainer);
+ document.body.appendChild(tooltip);
+
+ (tooltipShowButton as HTMLButtonElement).click();
+
+ expect((tooltipShowButton as HTMLElement).innerText).toBe('Show less');
+ expect(tooltip.querySelectorAll('.hidden')).toHaveLength(0);
+ expect(tooltipShowButton).not.toHaveClass('ps-tooltip-compact');
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/tooltip/tests/createToolTip.ts b/packages/extension/src/contentScript/popovers/tooltip/tests/createToolTip.ts
new file mode 100644
index 000000000..82776b1ad
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/tooltip/tests/createToolTip.ts
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import createTooltip from '../createTooltip';
+
+describe('createTooltip', () => {
+ it('should be an instance of HTMLDivElement', () => {
+ const response = {
+ isInspecting: true,
+ };
+ const iframe = document.createElement('iframe');
+ const tooltip = createTooltip(iframe, response, 0, 0);
+ document.body.appendChild(tooltip);
+
+ expect(tooltip instanceof HTMLDivElement).toBe(true);
+ });
+
+ it('child element should contain required elements, classes and attributes', () => {
+ const response = {
+ isInspecting: true,
+ };
+ const iframe = document.createElement('iframe');
+ const tooltip = createTooltip(iframe, response, 0, 0);
+ document.body.appendChild(tooltip);
+
+ expect(tooltip.popover).toBe('manual');
+ expect(tooltip.classList.contains('ps-tooltip')).toBe(true);
+ expect(tooltip.querySelectorAll('.ps-content')).toHaveLength(1);
+ expect(tooltip.querySelectorAll('p')).toHaveLength(9);
+ expect(tooltip.querySelectorAll('strong')).toHaveLength(9);
+ });
+
+ it('should contain the specified text', () => {
+ const response = {
+ isInspecting: true,
+ };
+ const iframe = document.createElement('iframe');
+ const tooltip = createTooltip(iframe, response, 0, 0);
+ document.body.appendChild(tooltip);
+
+ const infos = tooltip.querySelectorAll('p');
+
+ // First tooltip info.
+ expect(infos[0].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Type: Hidden iframe'
+ );
+
+ // Second tooltip info.
+ expect(infos[1].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Origin: empty'
+ );
+
+ // Third tooltip info.
+ expect(infos[2].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Visible iframes: 0'
+ );
+
+ // Fourth tooltip info.
+ expect(infos[3].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Hidden iframes: 0'
+ );
+
+ // Fifth tooltip info.
+ expect(infos[4].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'First-party cookies: 0'
+ );
+
+ // Sixth tooltip info.
+ expect(infos[5].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Third-party cookies: 0'
+ );
+
+ // Sixth tooltip info.
+ expect(infos[6].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Blocked cookies: 0'
+ );
+
+ // Seventh tooltip info.
+ expect(infos[7].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Belongs to RWS: N/A'
+ );
+
+ // Eighth tooltip info.
+ expect(infos[8].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Allowed Features (PS related): Unknown'
+ );
+ });
+});
diff --git a/packages/extension/src/contentScript/popovers/tooltip/tests/createToolTipHTML.ts b/packages/extension/src/contentScript/popovers/tooltip/tests/createToolTipHTML.ts
new file mode 100644
index 000000000..bde5e807b
--- /dev/null
+++ b/packages/extension/src/contentScript/popovers/tooltip/tests/createToolTipHTML.ts
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import createTooltipHTML from '../createTooltipHTML';
+import {
+ getInfo,
+ getInfoAttributes,
+} from '../../../utils/test-data/getToolTipInfoData';
+
+describe('createTooltipHTML', () => {
+ it('should contain "p" and "strong" tag elements', () => {
+ const infoHTMLElement = createTooltipHTML(getInfo(), getInfoAttributes());
+ document.body.appendChild(infoHTMLElement);
+
+ expect(infoHTMLElement instanceof HTMLElement).toBe(true);
+ expect(infoHTMLElement.querySelectorAll('p')).toHaveLength(8);
+ expect(infoHTMLElement.querySelectorAll('strong')).toHaveLength(8);
+ });
+
+ it('should contain the specified text', () => {
+ const infoHTMLElement = createTooltipHTML(getInfo(), getInfoAttributes());
+ document.body.appendChild(infoHTMLElement);
+
+ const infos = infoHTMLElement.querySelectorAll('p');
+
+ // First tooltip info.
+ expect(infos[0].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Type: iframe'
+ );
+
+ // Second tooltip info.
+ expect(infos[1].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Origin: about:blank'
+ );
+
+ // Third tooltip info.
+ expect(infos[2].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Visible iframes: 2'
+ );
+
+ // Fourth tooltip info.
+ expect(infos[3].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Hidden iframes: 3'
+ );
+
+ // Fifth tooltip info.
+ expect(infos[4].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'First-party cookies: 4'
+ );
+
+ // Sixth tooltip info.
+ expect(infos[5].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Third-party cookies: 5'
+ );
+
+ // Sixth tooltip info.
+ expect(infos[6].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Belongs to RWS: Yes'
+ );
+
+ // Seventh tooltip info.
+ expect(infos[7].textContent?.trim().replace(/\s+/g, ' ')).toBe(
+ 'Allowed Features (PS related): attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, run-ad-auction, shared-storage, shared-storage-select-url'
+ );
+
+ // Seventh tooltip info attributes.
+ const elementWithAttr = infoHTMLElement.querySelector(
+ '.ps-allowed-features'
+ );
+ expect(elementWithAttr?.getAttribute('data-compact-allowed-features')).toBe(
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, ...'
+ );
+ expect(
+ elementWithAttr?.getAttribute('data-expanded-allowed-features')
+ ).toBe(
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, run-ad-auction, shared-storage, shared-storage-select-url'
+ );
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/test-data/compareFrameSource.ts b/packages/extension/src/contentScript/utils/test-data/compareFrameSource.ts
new file mode 100644
index 000000000..0d70129a9
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/test-data/compareFrameSource.ts
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const expectedCases = [
+ {
+ origin: 'https://www.example.com', // from PS panel sidebar.
+ src: 'https://www.example.com/some/path',
+ toBe: true,
+ },
+ {
+ origin: 'http://www.example.com',
+ src: 'https://www.example.com/some/path',
+ toBe: true,
+ },
+ {
+ origin: 'www.example.com',
+ src: 'https://www.example.com/some/path',
+ toBe: true,
+ },
+ {
+ origin: 'example.com',
+ src: 'https://www.example.com/some/path',
+ toBe: true,
+ },
+ {
+ origin: 'https://bbc.com/',
+ src: 'https://www.bbc.com',
+ toBe: true,
+ },
+];
+
+export const unexpectedCases = [
+ {
+ origin: 'https://www.different.com',
+ src: 'https://www.example.com/some/path',
+ toBe: false,
+ },
+ {
+ origin: 'http://www.different.com',
+ src: 'https://www.example.com/some/path',
+ toBe: false,
+ },
+ {
+ origin: 'www.different.com',
+ src: 'https://www.example.com/some/path',
+ toBe: false,
+ },
+];
+
+export const edgeCases = [
+ {
+ origin: '',
+ src: '',
+ toBe: true,
+ },
+ {
+ origin: 'https://www.example.com',
+ src: '',
+ toBe: false,
+ },
+];
+
+export const realCases = [
+ {
+ origin: 'https://a4621041136.cdn.optimizely.com',
+ src: 'https://a4621041136.cdn.optimizely.com/client_storage/a4621041136.html',
+ toBe: true,
+ },
+ {
+ origin:
+ 'https://05700d83f33eb7346a37437dfe41f3f9.safeframe.googlesyndication.com',
+ src: 'https://05700d83f33eb7346a37437dfe41f3f9.safeframe.googlesyndication.com/safeframe/1-0-40/html/container.html',
+ toBe: true,
+ },
+ {
+ origin: 'https://elb.the-ozone-project.com',
+ src: 'https://elb.the-ozone-project.com/static/load-cookie.html?gdpr=0&gdpr_consent=&usp_consent=1YNN&pubcid=88e843a3-17fc-4662-a021-55d84c00c835&publisherId=OZONEBBC4784&siteId=8890582654&cb=1696009943052&bidder=ozone',
+ toBe: true,
+ },
+ {
+ origin: 'https://imasdk.googleapis.com',
+ src: 'https://imasdk.googleapis.com/js/core/bridge3.593.1_debug_en.html#goog_2122308160',
+ toBe: true,
+ },
+ {
+ origin: 'https://ads.pubmatic.com',
+ src: 'https://ads.pubmatic.com/AdServer/js/user_sync.html?kdntuid=1&p=160262&us_privacy=1---',
+ toBe: true,
+ },
+ {
+ origin: 'https://emp.bbc.com',
+ src: '//emp.bbc.com/emp/SMPj/2.50.7/iframe.html',
+ toBe: true,
+ },
+ {
+ origin: 'https://pagead2.googlesyndication.com',
+ src: 'https://pagead2.googlesyndication.com/pagead/s/cookie_push_onload.html#aHR0cHM6Ly9hLnRyaWJhbGZ1c2lvbi5jb20vaS5tYXRjaD9wPWI2JnU9Q0FFU0VGV2o1NXBDdnpPaXhUMTU3N09aYTBvJmdvb2dsZV9jdmVyPTEmZ29vZ2xlX3B1c2g9QVhjb09tU2plTnFoV0RWS3FQemdVTlAtXzdEandPTUp1dW5PNEdJeGlJczNvZ3BOb2g0YnhkZ3lBVWUwdWc0dGp0a01yVDZ0UHhVX05hZFRvbENzY3VPV1VEc2oycFY0Z1FYNndrQXpCanJZdzJ6ZklsNFNzTDFWWlE3eHcyVjNtalUzUmhSb3RPN0xQSmI5NlJERmJrRkhzRFUmcmVkaXJlY3Q9aHR0cHMlM0EvL2NtLmcuZG91YmxlY2xpY2submV0L3BpeGVsJTNGZ29vZ2xlX25pZCUzRGV4cCUyNmdvb2dsZV9wdXNoJTNEQVhjb09tU2plTnFoV0RWS3FQemdVTlAtXzdEandPTUp1dW5PNEdJeGlJczNvZ3BOb2g0YnhkZ3lBVWUwdWc0dGp0a01yVDZ0UHhVX05hZFRvbENzY3VPV1VEc2oycFY0Z1FYNndrQXpCanJZdzJ6ZklsNFNzTDFWWlE3eHcyVjNtalUzUmhSb3RPN0xQSmI5NlJERmJrRkhzRFUlMjZnb29nbGVfdWxhJTNEMjc4Njk1NCUyNmdvb2dsZV9obSUzRCUyNFRGX1VTRVJfSURfRU5DJTI0,aHR0cHM6Ly9jMS5hZGZvcm0ubmV0L3NlcnZpbmcvY29va2llL21hdGNoLz9wYXJ0eT0xJmdvb2dsZV9naWQ9Q0FFU0VDS1lIN2tpc3cwb0NqVEZHcnRqTEpnJmdvb2dsZV9jdmVyPTEmZ29vZ2xlX3B1c2g9QVhjb09tUTBBd1BzSzZXVmxYRExoVWJ4TmtWX0J2cEwyRnVKQkFmYjl6UHAyMzlXd3A2NE5FTHJiaDc3TlBDU0pfNm5tZkgtSDlSQVhQLUdkdHc4Y3R5QzFPSF9SNkJ2MUVoQ3pfNFp6TWJ5SkdFa3ZtR3FaVGNtSndjRWw0U1lMaV9ENFNkSlIxbk5YREtheDlyd3pMTkp3dw==,aHR0cHM6Ly9jcy5jaG9jb2xhdGVwbGF0Zm9ybS5jb20vcHViP3BpZD1lYmRhJmdvb2dsZV9naWQ9Q0FFU0VOc1lheFhJOVFzbEJwOUwzMkw4QVpnJmdvb2dsZV9jdmVyPTEmZ29vZ2xlX3B1c2g9QVhjb09tUVR5VEhZSGVQeHhCX1V2X0VmTlRpUlFMb1RQOGFmcUZaRHBuRUc4UDVEZ0hoU2VhdzZEakQ5eUF6SlJnVm5tTmphelgwR1NjbDVJQ2tiZm1mOFRfRmhySzUtdDVWQ0dYUnJBdFA2NWVuT092RHdQUjVoQVBaWkxrczlpR1lhTEFtRk0zS0tubl9YMUZFTmZpY0h3ZHM=,aHR0cHM6Ly9vbmV0YWctc3lzLmNvbS9tYXRjaC8_aW50X2lkPTEwNiZyZWRpcj0xJmdvb2dsZV9naWQ9Q0FFU0VDZkViSFY5R3Z3amlLU0pRM3BVeENZJmdvb2dsZV9jdmVyPTEmZ29vZ2xlX3B1c2g9QVhjb09tU1BEVXRPdGxSWWgtTFM0VVRRWGVGVl9YYlA0X0FpQng2R05LNWxLcWxwUUw5enRPbFZKNWhtQktZM1Z3OWVtN2dsb21MZzVHZmdDRDZLREFYVi1ad0J1LWRZX1ladXlmbzljRXhoZWU4U2VrUWJhSUlsWUZPWEtwMlpzX1RDUl9VY0MyTnAtVHRCdnBRQUxIMzJjSExX,aHR0cHM6Ly9jbS5nLmRvdWJsZWNsaWNrLm5ldC9waXhlbC9hdHRyP2Q9QUhORjEzS3F3Q0xDOE1tc19KSEpBOEFqX29uVjFPdDE1Q0xQSF9jbnluemU4YVozYTd6cms4N01HUQ==',
+ toBe: true,
+ },
+];
diff --git a/packages/extension/src/contentScript/utils/test-data/getToolTipInfoData.ts b/packages/extension/src/contentScript/utils/test-data/getToolTipInfoData.ts
new file mode 100644
index 000000000..ef113b365
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/test-data/getToolTipInfoData.ts
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Function to get new info object.
+export const getInfo = () => {
+ return {
+ Type: 'iframe',
+ Origin: 'about:blank',
+ 'Visible iframes': '2',
+ 'Hidden iframes': '3',
+ 'First-party cookies': '4',
+ 'Third-party cookies': '5',
+ 'Belongs to RWS': 'Yes',
+ 'Allowed Features (PS related)':
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, run-ad-auction, shared-storage, shared-storage-select-url',
+ };
+};
+
+// Function to get new info attribute object.
+export const getInfoAttributes = () => {
+ return {
+ allowedFeaturesInCompactView:
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, ...',
+ allowedFeatureInExpandedView:
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, run-ad-auction, shared-storage, shared-storage-select-url',
+ };
+};
+
+// Values to pass to getTooltipInfoData.
+export const getTooltipInfoDataProp = {
+ frameType: 'iframe',
+ origin: 'https://example.com',
+ numberOfVisibleFrames: 0,
+ numberOfHiddenFrames: 0,
+ numberOfFirstPartyCookies: 0,
+ numberOfThirdPartyCookies: 0,
+ belongsToRWS: 'No',
+ allowedFeatures: 'N/A',
+ displayShowMoreButton: false,
+};
+
+// Expected result.
+export const expectedResult = {
+ info: {
+ Type: 'iframe',
+ Origin:
+ 'https://example.com ',
+ 'Visible iframes': '0',
+ 'Hidden iframes': '0',
+ 'First-party cookies': '0',
+ 'Third-party cookies': '0',
+ 'Belongs to RWS': 'No',
+ 'Allowed Features (PS related)': 'N/A',
+ 'Blocked cookies': '0',
+ 'Blocked reasons': '',
+ },
+ attr: {
+ allowedFeaturesInCompactView: 'N/A',
+ allowedFeatureInExpandedView: 'N/A',
+ },
+};
+
+// Reset expectedResult to its initial state.
+export const resetExpectedResult = () => {
+ expectedResult.info = {
+ Type: 'iframe',
+ Origin:
+ 'https://example.com ',
+ 'Visible iframes': '0',
+ 'Hidden iframes': '0',
+ 'First-party cookies': '0',
+ 'Third-party cookies': '0',
+ 'Belongs to RWS': 'No',
+ 'Allowed Features (PS related)': 'N/A',
+ 'Blocked cookies': '0',
+ 'Blocked reasons': '',
+ };
+ expectedResult.attr = {
+ allowedFeaturesInCompactView: 'N/A',
+ allowedFeatureInExpandedView: 'N/A',
+ };
+};
diff --git a/packages/extension/src/contentScript/utils/test-data/isOnRWSData.ts b/packages/extension/src/contentScript/utils/test-data/isOnRWSData.ts
new file mode 100644
index 000000000..edf3e9c76
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/test-data/isOnRWSData.ts
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const rws = {
+ sets: [
+ {
+ contact: 'dmarti@raptive.com',
+ primary: 'https://cafemedia.com',
+ associatedSites: [
+ 'https://cardsayings.net',
+ 'https://nourishingpursuits.com',
+ ],
+ rationaleBySite: {
+ 'https://cardsayings.net': 'Co-branded content site',
+ 'https://nourishingpursuits.com': 'Co-branded content site',
+ },
+ },
+ {
+ primary: 'https://bild.de',
+ contact: 'robert.blanck@axelspringer.com',
+ associatedSites: [
+ 'https://welt.de',
+ 'https://autobild.de',
+ 'https://computerbild.de',
+ 'https://wieistmeineip.de',
+ ],
+ serviceSites: ['https://www.asadcdn.com'],
+ rationaleBySite: {
+ 'https://welt.de': 'News Website welt.de',
+ 'https://autobild.de': 'Special Interest Website Autobild',
+ 'https://computerbild.de': 'Special Interest Website Computerbild',
+ 'https://wieistmeineip.de':
+ 'Internet speed Measurement Website of Computerbild',
+ 'https://www.asadcdn.com': 'CDN for Ad Files - Frequency Capping',
+ },
+ },
+ {
+ primary: 'https://hapara.com',
+ contact: 'support@hapara.com',
+ associatedSites: [
+ 'https://teacherdashboard.com',
+ 'https://mystudentdashboard.com',
+ ],
+ rationaleBySite: {
+ 'https://teacherdashboard.com': 'Portal for Hapara teachers',
+ 'https://mystudentdashboard.com': 'Portal for Hapara students',
+ },
+ },
+ {
+ contact: 'support@songstats.com',
+ primary: 'https://songstats.com',
+ associatedSites: ['https://songshare.com'],
+ rationaleBySite: {
+ 'https://songshare.com': 'Specialized Platform for Music Smart Links',
+ },
+ },
+ {
+ contact: 'prashant.tiwari@htdigital.in',
+ primary: 'https://hindustantimes.com',
+ associatedSites: ['https://livemint.com'],
+ rationaleBySite: {
+ 'https://livemint.com': 'Specialized Platform for economics',
+ },
+ },
+ {
+ contact: 'alexey@landyrev.com',
+ primary: 'https://landyrev.com',
+ associatedSites: ['https://landyrev.ru'],
+ rationaleBySite: {
+ 'https://landyrev.ru': "Same publisher's website in a different region",
+ },
+ },
+ ],
+};
+
+export default rws;
diff --git a/packages/extension/src/contentScript/utils/tests/getAllowedFeature.ts b/packages/extension/src/contentScript/utils/tests/getAllowedFeature.ts
new file mode 100644
index 000000000..32124a179
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/getAllowedFeature.ts
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import getAllowedFeatures from '../getAllowedFeatures';
+
+let frameAllowedFeatures: string[];
+let supportsFeaturePolicy: boolean;
+
+describe('getAllowedFeatures', () => {
+ // Since feature policy is not supported.
+ beforeAll(() => {
+ // @ts-ignore
+ globalThis.document.createElement = jest.fn(() => {
+ if (supportsFeaturePolicy) {
+ return {
+ featurePolicy: {
+ allowedFeatures: () => {
+ return frameAllowedFeatures;
+ },
+ },
+ };
+ }
+
+ return {};
+ });
+ });
+
+ it('should return array of PS related allowed features', () => {
+ supportsFeaturePolicy = true;
+ frameAllowedFeatures = [
+ 'accelerometer',
+ 'autoplay',
+ 'clipboard-write',
+ 'encrypted-media',
+ 'gyroscope',
+ 'picture-in-picture',
+ 'web-share',
+ 'attribution-reporting',
+ 'browsing-topics',
+ 'interest-cohort',
+ 'join-ad-interest-group',
+ 'private-aggregation',
+ 'run-ad-auction',
+ 'shared-storage',
+ 'shared-storage-select-url',
+ ];
+
+ const expectedFeatures = [
+ 'attribution-reporting',
+ 'browsing-topics',
+ 'interest-cohort',
+ 'join-ad-interest-group',
+ 'private-aggregation',
+ 'run-ad-auction',
+ 'shared-storage',
+ 'shared-storage-select-url',
+ ];
+
+ const iframe = document.createElement('iframe');
+ const allowedFeatures = getAllowedFeatures(iframe);
+
+ expect(allowedFeatures).toEqual(expectedFeatures);
+ });
+
+ it('should return "N/A" as no features are allowed', () => {
+ supportsFeaturePolicy = true;
+ frameAllowedFeatures = [];
+
+ const iframe = document.createElement('iframe');
+ const allowedFeatures = getAllowedFeatures(iframe);
+
+ expect(allowedFeatures).toBe('N/A');
+ });
+
+ it('should return "Unknown" if feature policy is not supported', () => {
+ supportsFeaturePolicy = false;
+ frameAllowedFeatures = [];
+
+ const iframe = document.createElement('iframe');
+ const allowedFeatures = getAllowedFeatures(iframe);
+
+ expect(allowedFeatures).toBe('Unknown');
+ });
+
+ afterAll(() => {
+ globalThis.document.createElement =
+ undefined as unknown as typeof document.createElement;
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/getFrameCount.ts b/packages/extension/src/contentScript/utils/tests/getFrameCount.ts
new file mode 100644
index 000000000..9aad7650c
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/getFrameCount.ts
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import getFrameCount from '../getFrameCount';
+
+const mockGetBoundingClientRect = (height: number, width: number) => {
+ return {
+ height,
+ width,
+ } as DOMRect;
+};
+
+describe('getFrameCount', () => {
+ it('should match the total number iframes', () => {
+ // No need to mock getBoundingClientRect, as we only need total frame count.
+
+ const hiddenIframe = document.createElement('iframe');
+ const visibleIframe = document.createElement('iframe');
+
+ const iframes = [hiddenIframe, visibleIframe];
+ const numberOfFrames = getFrameCount(iframes).numberOfFrames;
+
+ expect(numberOfFrames).toBe(2);
+ });
+
+ it('should match the total number hidden iframes', () => {
+ // No need to mock getBoundingClientRect as it returns 0 only.
+
+ const hiddenIframe = document.createElement('iframe');
+ const iframes = [hiddenIframe, hiddenIframe];
+ const numberOfHiddenFrames = getFrameCount(iframes).numberOfFrames;
+
+ expect(numberOfHiddenFrames).toBe(2);
+ });
+
+ it('should match the total number visible iframes', () => {
+ const visibleIframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ visibleIframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(20, 30)
+ );
+
+ const iframes = [visibleIframe, visibleIframe, visibleIframe];
+ const numberOfVisibleFrames = getFrameCount(iframes).numberOfVisibleFrames;
+
+ expect(numberOfVisibleFrames).toBe(3);
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/getFrameOrigin.ts b/packages/extension/src/contentScript/utils/tests/getFrameOrigin.ts
new file mode 100644
index 000000000..573caf7a2
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/getFrameOrigin.ts
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Internal dependencies.
+ */
+import getFrameOrigin from '../getFrameOrigin';
+
+describe('getFrameOrigin', () => {
+ it('should return frame origin', () => {
+ const attributes = [
+ { src: 'https://www.example.com', width: '0', height: '0' },
+ { src: 'https://www.example.com/', width: '0', height: '100' },
+ { src: 'https://www.example.com/blog', width: '100', height: '0' },
+ { src: 'https://www.example.com/post/123', width: '100', height: '100' },
+ { src: 'https://www.example.com?post=123', width: '50', height: '150' },
+ ];
+
+ attributes.forEach((attribute) => {
+ // Call the function with the iframe attributes and expect the returned string to match the origin
+ expect(getFrameOrigin(attribute)).toBe('https://www.example.com');
+ });
+ });
+
+ it('should return an empty string if origin is not found', () => {
+ const attributes = [
+ { src: '', width: '0', height: '100' },
+ { src: '/post/123', width: '100', height: '0' },
+ { src: 'example.com', width: '100', height: '100' },
+ ];
+
+ attributes.forEach((attribute) => {
+ // Call the function with the iframe attributes and expect the returned string to match the origin
+ expect(getFrameOrigin(attribute)).toBe('');
+ });
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/getFrameType.ts b/packages/extension/src/contentScript/utils/tests/getFrameType.ts
new file mode 100644
index 000000000..cb909338f
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/getFrameType.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import getFrameType from '../getFrameType';
+
+describe('getFrameType', () => {
+ it('should return frame type (Hidden iframe)', () => {
+ const iframe = document.createElement('iframe');
+
+ expect(getFrameType(true, null, 'BODY')).toBe('Hidden iframe');
+ expect(getFrameType(true, null, 'DIV')).toBe('Hidden iframe');
+ expect(getFrameType(true, iframe, 'BODY')).toBe('Hidden iframe');
+ expect(getFrameType(true, iframe, 'DIV')).toBe('Hidden iframe');
+ });
+
+ it('should return frame type (Nested iframe)', () => {
+ const iframe = document.createElement('iframe');
+
+ expect(getFrameType(false, iframe, 'BODY')).toBe('Nested iframe');
+ expect(getFrameType(false, iframe, 'DIV')).toBe('Nested iframe');
+ });
+
+ it('should return frame type (Main frame)', () => {
+ expect(getFrameType(false, null, 'BODY')).toBe('Main frame');
+ });
+
+ it('should return frame type (iframe)', () => {
+ expect(getFrameType(false, null, 'DIV')).toBe('iframe');
+ expect(getFrameType(false, null, 'SPAN')).toBe('iframe');
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/getToolTipInfoData.ts b/packages/extension/src/contentScript/utils/tests/getToolTipInfoData.ts
new file mode 100644
index 000000000..0733ae56d
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/getToolTipInfoData.ts
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import getTooltipInfoData from '../getTooltipInfoData';
+import {
+ getTooltipInfoDataProp,
+ expectedResult,
+ resetExpectedResult,
+} from '../test-data/getToolTipInfoData';
+
+describe('getTooltipInfoData', () => {
+ it('should return an object containing data for tooltip', () => {
+ resetExpectedResult();
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ getTooltipInfoDataProp.origin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ getTooltipInfoDataProp.belongsToRWS,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expect(result).toEqual(expectedResult);
+ });
+
+ it('should return an object with frame type data', () => {
+ resetExpectedResult();
+ const frameTypes = [
+ 'Hidden iframe',
+ 'Nested iframe',
+ 'Main frame',
+ 'iframe',
+ ];
+
+ frameTypes.forEach((frameType) => {
+ const result = getTooltipInfoData(
+ frameType,
+ getTooltipInfoDataProp.origin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ getTooltipInfoDataProp.belongsToRWS,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expectedResult.info['Type'] = frameType;
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ it('should return an object with frame origin data', () => {
+ resetExpectedResult();
+ const frameOrigins = [
+ 'https://example.com',
+ 'https://google.com',
+ 'about:blank',
+ '',
+ ];
+
+ frameOrigins.forEach((frameOrigin) => {
+ resetExpectedResult();
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ frameOrigin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ getTooltipInfoDataProp.belongsToRWS,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ if ('' === frameOrigin) {
+ expectedResult.info['Origin'] = 'empty';
+ } else if ('about:blank' === frameOrigin) {
+ expectedResult.info['Origin'] = 'about:blank';
+ } else {
+ expectedResult.info[
+ 'Origin'
+ ] = `${frameOrigin} `;
+ }
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ it('should return an object with visible frame count', () => {
+ resetExpectedResult();
+ const visibleFrameCounts = [0, 1, 2, 3];
+
+ visibleFrameCounts.forEach((visibleFrameCount) => {
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ getTooltipInfoDataProp.origin,
+ visibleFrameCount,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ getTooltipInfoDataProp.belongsToRWS,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expectedResult.info['Visible iframes'] = String(visibleFrameCount);
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ it('should return an object with hidden frame count', () => {
+ resetExpectedResult();
+ const hiddenFrameCounts = [0, 1, 2, 3];
+
+ hiddenFrameCounts.forEach((hiddenFrameCount) => {
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ getTooltipInfoDataProp.origin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ hiddenFrameCount,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ getTooltipInfoDataProp.belongsToRWS,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expectedResult.info['Hidden iframes'] = String(hiddenFrameCount);
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ it('should return an object with first party cookie count', () => {
+ resetExpectedResult();
+ const numberOfFirstPartyCookies = [0, 1, 2, 3];
+
+ numberOfFirstPartyCookies.forEach((cookieCount) => {
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ getTooltipInfoDataProp.origin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ cookieCount,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ getTooltipInfoDataProp.belongsToRWS,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expectedResult.info['First-party cookies'] = String(cookieCount);
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ it('should return an object with third party cookie count', () => {
+ resetExpectedResult();
+ const numberOfThirdPartyCookies = [0, 1, 2, 3];
+
+ numberOfThirdPartyCookies.forEach((cookieCount) => {
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ getTooltipInfoDataProp.origin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ cookieCount,
+ getTooltipInfoDataProp.belongsToRWS,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expectedResult.info['Third-party cookies'] = String(cookieCount);
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ it('should return an object with RWS data', () => {
+ resetExpectedResult();
+ const belongsToRWS = ['Yes', 'No'];
+
+ belongsToRWS.forEach((rws) => {
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ getTooltipInfoDataProp.origin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ rws,
+ getTooltipInfoDataProp.allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expectedResult.info['Belongs to RWS'] = rws;
+
+ expect(result).toEqual(expectedResult);
+ });
+ });
+
+ it('should return an object with PS related allowed features data', () => {
+ resetExpectedResult();
+ const allowedFeatures = [
+ 'attribution-reporting',
+ 'browsing-topics',
+ 'interest-cohort',
+ 'join-ad-interest-group',
+ 'private-aggregation',
+ 'run-ad-auction',
+ 'shared-storage',
+ 'shared-storage-select-url',
+ ];
+
+ const result = getTooltipInfoData(
+ getTooltipInfoDataProp.frameType,
+ getTooltipInfoDataProp.origin,
+ getTooltipInfoDataProp.numberOfVisibleFrames,
+ getTooltipInfoDataProp.numberOfHiddenFrames,
+ getTooltipInfoDataProp.numberOfFirstPartyCookies,
+ getTooltipInfoDataProp.numberOfThirdPartyCookies,
+ getTooltipInfoDataProp.belongsToRWS,
+ allowedFeatures,
+ getTooltipInfoDataProp.displayShowMoreButton,
+ 0,
+ ''
+ );
+
+ expectedResult.info['Allowed Features (PS related)'] =
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, run-ad-auction, shared-storage, shared-storage-select-url';
+
+ expectedResult.attr['allowedFeaturesInCompactView'] =
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, ...';
+
+ expectedResult.attr['allowedFeatureInExpandedView'] =
+ 'attribution-reporting, browsing-topics, interest-cohort, join-ad-interest-group, private-aggregation, run-ad-auction, shared-storage, shared-storage-select-url';
+
+ expect(result).toEqual(expectedResult);
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/isElementInViewPort.ts b/packages/extension/src/contentScript/utils/tests/isElementInViewPort.ts
new file mode 100644
index 000000000..b11b2afd6
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/isElementInViewPort.ts
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import isElementVisibleInViewport from '../isElementInViewport';
+
+const { innerHeight, innerWidth } = window;
+const mockGetBoundingClientRect = (
+ top: number,
+ left: number,
+ right: number,
+ bottom: number
+) => {
+ return {
+ top,
+ left,
+ right,
+ bottom,
+ } as DOMRect;
+};
+
+describe('isElementVisibleInViewport', () => {
+ it('should return true since div is partially visible in viewport and partiallyVisible is set to true', () => {
+ const div = document.createElement('div');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ div.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(
+ innerHeight - 20,
+ innerWidth - 20,
+ innerWidth - 20 + 50,
+ innerHeight - 20 + 50
+ )
+ );
+
+ expect(isElementVisibleInViewport(div, true)).toBe(true);
+ });
+
+ it('should return true since div is fully visible in viewport', () => {
+ const div = document.createElement('div');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ div.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(
+ innerHeight - 100,
+ innerWidth - 100,
+ innerWidth - 100 + 50,
+ innerHeight - 100 + 50
+ )
+ );
+
+ expect(isElementVisibleInViewport(div, true)).toBe(true);
+ });
+
+ it('should return false since div is not fully visible in viewport and partiallyVisible is set to false', () => {
+ const div = document.createElement('div');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ div.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(
+ innerHeight - 20,
+ innerWidth - 20,
+ innerWidth - 20 + 50,
+ innerHeight - 20 + 50
+ )
+ );
+
+ expect(isElementVisibleInViewport(div, false)).toBe(false);
+ });
+
+ it('should return true since div is fully not visible in viewport', () => {
+ const div = document.createElement('div');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ div.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(
+ innerHeight + 50,
+ innerWidth + 50,
+ innerWidth + 50 + 50,
+ innerHeight + 50 + 50
+ )
+ );
+
+ expect(isElementVisibleInViewport(div, true)).toBe(false);
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/isFrameHidden.ts b/packages/extension/src/contentScript/utils/tests/isFrameHidden.ts
new file mode 100644
index 000000000..42abab7cd
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/isFrameHidden.ts
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import isFrameHidden from '../isFrameHidden';
+
+const mockGetBoundingClientRect = (height: number, width: number) => {
+ return {
+ height,
+ width,
+ } as DOMRect;
+};
+
+describe('isFrameHidden', () => {
+ it('should return true since iframe has no height', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(0, 100)
+ );
+
+ expect(isFrameHidden(iframe)).toEqual(true);
+ });
+
+ it('should return true since iframe has no width', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(100, 0)
+ );
+
+ expect(isFrameHidden(iframe)).toEqual(true);
+ });
+
+ it('should return true since iframe has no height and width', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(0, 0)
+ );
+
+ expect(isFrameHidden(iframe)).toEqual(true);
+ });
+
+ it('should return false since visibleIframeOne is visible', () => {
+ const iframe = document.createElement('iframe');
+
+ // Mock getBoundingClientRect since it always returns 0.
+ iframe.getBoundingClientRect = jest.fn(() =>
+ mockGetBoundingClientRect(20, 30)
+ );
+
+ expect(isFrameHidden(iframe)).toEqual(false);
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/isFrameInsideFrame.ts b/packages/extension/src/contentScript/utils/tests/isFrameInsideFrame.ts
new file mode 100644
index 000000000..9436e7c40
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/isFrameInsideFrame.ts
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import isFrameInsideFrame from '../isFrameInsideFrame';
+
+describe('isFrameInsideFrame', () => {
+ it('should return true when frames are inside', () => {
+ // Parent frame.
+ const parentIframe = document.createElement('iframe');
+ document.body.appendChild(parentIframe);
+
+ // Create new contentDocument for parent iframe.
+ const contentDocument = document.implementation.createHTMLDocument();
+
+ Object.defineProperty(parentIframe, 'contentDocument', {
+ value: contentDocument,
+ });
+
+ // Child frame.
+ const childIframe = document.createElement('iframe');
+ childIframe.setAttribute('src', 'https://example.com');
+ contentDocument.body.appendChild(childIframe);
+
+ const result = isFrameInsideFrame(parentIframe, 'https://example.com');
+ expect(result).toBe(true);
+ });
+
+ it('should return false since there are no frames inside it', () => {
+ // Parent frame.
+ const parentIframe = document.createElement('iframe');
+ document.body.appendChild(parentIframe);
+
+ // Create new contentDocument for parent iframe.
+ const contentDocument = document.implementation.createHTMLDocument();
+
+ Object.defineProperty(parentIframe, 'contentDocument', {
+ value: contentDocument,
+ });
+
+ const result = isFrameInsideFrame(parentIframe, 'https://example.com');
+ expect(result).toBe(false);
+ });
+
+ it('should return false since there is no frame src match origin', () => {
+ // Parent frame.
+ const parentIframe = document.createElement('iframe');
+ document.body.appendChild(parentIframe);
+
+ // Create new contentDocument for parent iframe.
+ const contentDocument = document.implementation.createHTMLDocument();
+
+ Object.defineProperty(parentIframe, 'contentDocument', {
+ value: contentDocument,
+ });
+
+ // Child frame.
+ const childIframe = document.createElement('iframe');
+ childIframe.setAttribute('src', 'https://domain.com');
+ contentDocument.body.appendChild(childIframe);
+
+ const result = isFrameInsideFrame(parentIframe, 'https://example.com');
+ expect(result).toBe(false);
+ });
+
+ it('should return true since at least one frame src match origin', () => {
+ // Parent frame.
+ const parentIframe = document.createElement('iframe');
+ document.body.appendChild(parentIframe);
+
+ // Create new contentDocument for parent iframe.
+ const contentDocument = document.implementation.createHTMLDocument();
+
+ Object.defineProperty(parentIframe, 'contentDocument', {
+ value: contentDocument,
+ });
+
+ // Child frames.
+ const childIframeOne = document.createElement('iframe');
+ const childIframeTwo = document.createElement('iframe');
+
+ childIframeOne.setAttribute('src', 'https://domain.com');
+ childIframeTwo.setAttribute('src', 'https://example.com');
+
+ contentDocument.body.appendChild(childIframeOne);
+ contentDocument.body.appendChild(childIframeTwo);
+
+ const result = isFrameInsideFrame(parentIframe, 'https://example.com');
+ expect(result).toBe(true);
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/isOnRWS.ts b/packages/extension/src/contentScript/utils/tests/isOnRWS.ts
new file mode 100644
index 000000000..acbbffbb7
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/isOnRWS.ts
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import SinonChrome from 'sinon-chrome';
+
+/**
+ * Internal dependencies.
+ */
+import isOnRWS from '../isOnRWS';
+import rws from '../test-data/isOnRWSData';
+
+describe('isOnRWS', () => {
+ beforeAll(() => {
+ globalThis.chrome = SinonChrome as unknown as typeof chrome;
+ globalThis.fetch = (): Promise =>
+ Promise.resolve({
+ json: () => Promise.resolve(rws),
+ } as Response);
+ });
+
+ it('should return true since the website belongs to RWS', async () => {
+ const urls = [
+ 'https://cafemedia.com',
+ 'https://bild.de',
+ 'https://hapara.com',
+ 'https://songstats.com',
+ 'https://hindustantimes.com',
+ ];
+
+ for (const url of urls) {
+ // eslint-disable-next-line no-await-in-loop
+ const result = await isOnRWS(url);
+
+ expect(result).toBe(true);
+ }
+ });
+
+ it('should return false since the website does not belong to RWS', async () => {
+ const urls = [
+ 'https://abc.example.com',
+ 'https://abc.helloworld.com',
+ 'https://helloworld.xyz',
+ ];
+
+ for (const url of urls) {
+ // eslint-disable-next-line no-await-in-loop
+ const result = await isOnRWS(url);
+
+ expect(result).toBe(false);
+ }
+ });
+
+ afterAll(() => {
+ globalThis.chrome = undefined as unknown as typeof chrome;
+ globalThis.fetch = undefined as unknown as typeof fetch;
+ });
+});
diff --git a/packages/extension/src/contentScript/utils/tests/remvoveTrailingSlash.ts b/packages/extension/src/contentScript/utils/tests/remvoveTrailingSlash.ts
new file mode 100644
index 000000000..fe6cfcc37
--- /dev/null
+++ b/packages/extension/src/contentScript/utils/tests/remvoveTrailingSlash.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * Internal dependencies.
+ */
+import removeTrailingSlash from '../removeTrailingSlash';
+
+describe('removeTrailingSlash', () => {
+ it('should return url with no trailing slash', () => {
+ const urls = ['https://example.com/', 'https://example.com'];
+ const urlWithNoTrailingSlash = 'https://example.com';
+
+ urls.forEach((url) => {
+ expect(removeTrailingSlash(url)).toBe(urlWithNoTrailingSlash);
+ });
+ });
+});
diff --git a/packages/extension/src/manifest.json b/packages/extension/src/manifest.json
index cc0477c57..ed59187d3 100644
--- a/packages/extension/src/manifest.json
+++ b/packages/extension/src/manifest.json
@@ -1,7 +1,7 @@
{
"name": "Privacy Sandbox Analysis Tool",
"description": "Tooling for understanding cookie usage and guidance on new privacy-preserving Chrome APIs.",
- "version": "0.6.0",
+ "version": "0.7.0",
"manifest_version": 3,
"icons": {
"16": "icons/icon-16.png",
@@ -38,7 +38,7 @@
},
"web_accessible_resources": [
{
- "resources": ["assets/data/*.json", "data/*json"],
+ "resources": ["assets/data/*.json", "data/*json", "report/index.html"],
"matches": ["*://*/*"]
}
]
diff --git a/packages/extension/src/serviceWorker/createCookieObject.ts b/packages/extension/src/serviceWorker/createCookieObject.ts
index 030b9ed6d..f0990cbf4 100644
--- a/packages/extension/src/serviceWorker/createCookieObject.ts
+++ b/packages/extension/src/serviceWorker/createCookieObject.ts
@@ -23,7 +23,10 @@ import {
getDomainFromUrl,
} from '@ps-analysis-tool/common';
import type { Protocol } from 'devtools-protocol';
-import isValidURL from './isValidURL';
+/**
+ * Internal dependencies
+ */
+import isValidURL from '../utils/isValidURL';
/**
* Create cookie object from ChromeStorage API cookie object, previously saved parsed cookie object if any, and recently captured request/response cookie header.
diff --git a/packages/extension/src/serviceWorker/index.ts b/packages/extension/src/serviceWorker/index.ts
index dd4dbf474..c8892240e 100644
--- a/packages/extension/src/serviceWorker/index.ts
+++ b/packages/extension/src/serviceWorker/index.ts
@@ -17,24 +17,35 @@
/**
* External dependencies.
*/
+import { Protocol } from 'devtools-protocol';
import {
type CookieDatabase,
type CookieData,
parseResponseReceivedExtraInfo,
parseRequestWillBeSentExtraInfo,
} from '@ps-analysis-tool/common';
-import { Protocol } from 'devtools-protocol';
/**
* Internal dependencies.
*/
-import parseResponseCookieHeader from './parseResponseCookieHeader';
-import parseRequestCookieHeader from './parseRequestCookieHeader';
import { fetchDictionary } from '../utils/fetchCookieDictionary';
-import { ALLOWED_NUMBER_OF_TABS } from '../constants';
+import {
+ ALLOWED_NUMBER_OF_TABS,
+ DEVTOOLS_CLOSE,
+ DEVTOOLS_OPEN,
+ DEVTOOLS_SET_JAVASCSCRIPT_COOKIE,
+ INITIAL_SYNC,
+ POPUP_CLOSE,
+ POPUP_OPEN,
+ SERVICE_WORKER_RELOAD_MESSAGE,
+ SERVICE_WORKER_TABS_RELOAD_COMMAND,
+ SET_TAB_TO_READ,
+ TABID_STORAGE,
+} from '../constants';
import SynchnorousCookieStore from '../store/synchnorousCookieStore';
-import canProcessCookies from '../utils/canProcessCookies';
import { getTab } from '../utils/getTab';
+import parseHeaders from '../utils/parseHeaders';
+import resetCookieBadgeText from '../store/utils/resetCookieBadgeText';
import getQueryParams from '../utils/getQueryParams';
import reloadCurrentTab from '../utils/reloadCurrentTab';
@@ -63,9 +74,8 @@ const ALLOWED_EVENTS = [
* @see https://developer.chrome.com/docs/extensions/reference/api/webRequest
*/
chrome.webRequest.onResponseStarted.addListener(
- (details: chrome.webRequest.WebResponseCacheDetails) => {
+ ({ tabId, url, responseHeaders, frameId, requestId }) => {
(async () => {
- const { tabId, url, responseHeaders, frameId } = details;
const tab = await getTab(tabId);
let tabUrl = syncCookieStore?.getTabUrl(tabId);
@@ -73,53 +83,22 @@ chrome.webRequest.onResponseStarted.addListener(
tabUrl = tab.pendingUrl;
}
- if (
- !canProcessCookies(tabMode, tabUrl, tabToRead, tabId, responseHeaders)
- ) {
- return;
- }
-
if (!cookieDB) {
cookieDB = await fetchDictionary();
}
- let cdpCookies: { [key: string]: Protocol.Network.Cookie[] };
-
- // Since we are using CDP we might as well use it to get the proper cookies in the request this will further reduce the load of domain calculation
- try {
- cdpCookies = await chrome.debugger.sendCommand(
- { tabId: tabId },
- 'Network.getCookies',
- { urls: [url] }
- );
- } catch (error) {
- // Fail silently
- }
-
- const cookies = responseHeaders?.reduce(
- (accumulator, header) => {
- if (
- header.name.toLowerCase() === 'set-cookie' &&
- header.value &&
- tabUrl &&
- cookieDB
- ) {
- const cookie = parseResponseCookieHeader(
- url,
- header.value,
- cookieDB,
- tabUrl,
- frameId,
- cdpCookies?.cookies ?? [],
- details.requestId
- );
-
- return [...accumulator, cookie];
- }
-
- return accumulator;
- },
- []
+ const cookies = await parseHeaders(
+ globalIsUsingCDP,
+ 'response',
+ tabToRead,
+ tabMode,
+ tabId,
+ url,
+ cookieDB,
+ tabUrl,
+ frameId,
+ requestId,
+ responseHeaders
);
if (!cookies || (cookies && cookies?.length === 0)) {
@@ -148,59 +127,29 @@ chrome.webRequest.onBeforeSendHeaders.addListener(
tabUrl = tab.pendingUrl;
}
- if (
- !canProcessCookies(tabMode, tabUrl, tabToRead, tabId, requestHeaders)
- ) {
- return;
- }
-
if (!cookieDB) {
cookieDB = await fetchDictionary();
}
- let cdpCookies: { [key: string]: Protocol.Network.Cookie[] };
-
- try {
- cdpCookies = await chrome.debugger.sendCommand(
- { tabId: tabId },
- 'Network.getCookies',
- { urls: [url] }
- );
- } catch (error) {
- // Fail silently
- }
-
- const cookies = requestHeaders?.reduce(
- (accumulator, header) => {
- if (
- header.name.toLowerCase() === 'cookie' &&
- header.value &&
- url &&
- tabUrl &&
- cookieDB
- ) {
- const cookieList = parseRequestCookieHeader(
- url,
- header.value,
- cookieDB,
- tabUrl,
- frameId,
- cdpCookies?.cookies ?? [],
- requestId
- );
-
- return [...accumulator, ...cookieList];
- }
-
- return accumulator;
- },
- []
+ const cookies = await parseHeaders(
+ globalIsUsingCDP,
+ 'request',
+ tabToRead,
+ tabMode,
+ tabId,
+ url,
+ cookieDB,
+ tabUrl,
+ frameId,
+ requestId,
+ requestHeaders
);
if (!cookies || (cookies && cookies?.length === 0)) {
return;
}
+ // Adds the cookies from the request headers to the cookies object.
syncCookieStore?.update(tabId, cookies);
})();
},
@@ -309,12 +258,11 @@ chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (changeInfo.status === 'loading' && tab.url) {
syncCookieStore?.removeCookieData(tabId);
}
-
try {
await chrome.tabs.sendMessage(tabId, {
tabId,
payload: {
- type: 'SERVICEWORKER::WEBPAGE::TABID_STORAGE',
+ type: TABID_STORAGE,
tabId,
},
});
@@ -407,25 +355,19 @@ chrome.runtime.onInstalled.addListener(async (details) => {
*/
// eslint-disable-next-line complexity
chrome.debugger.onEvent.addListener((source, method, params) => {
- if (!ALLOWED_EVENTS.includes(method)) {
- return;
- }
-
- let tabId = '';
-
- if (!source?.tabId) {
+ if (!ALLOWED_EVENTS.includes(method) || !source?.tabId || !params) {
return;
}
const url = syncCookieStore?.getTabUrl(source?.tabId);
- tabId = source?.tabId?.toString();
+ const tabId = source.tabId.toString();
- if (tabMode && tabMode !== 'unlimited' && tabToRead !== tabId) {
+ if (tabMode !== 'unlimited' && tabToRead !== tabId) {
return;
}
- if (method === 'Network.responseReceived' && params) {
+ if (method === 'Network.responseReceived') {
const request = params as Protocol.Network.ResponseReceivedEvent;
// To get domain from the request URL if not given in the cookie line.
@@ -441,19 +383,22 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
}
}
- if (method === 'Network.requestWillBeSentExtraInfo' && params) {
+ if (method === 'Network.requestWillBeSentExtraInfo') {
const requestParams =
params as Protocol.Network.RequestWillBeSentExtraInfoEvent;
- if (requestParams.associatedCookies.length === 0) {
+ const { associatedCookies, requestId } = requestParams;
+
+ if (associatedCookies.length === 0) {
return;
}
const cookies: CookieData[] = parseRequestWillBeSentExtraInfo(
- requestParams,
+ associatedCookies,
cookieDB ?? {},
requestIdToCDPURLMapping[tabId],
- url ?? ''
+ url ?? '',
+ requestId
);
if (cookies.length === 0) {
@@ -463,32 +408,44 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
syncCookieStore?.update(Number(tabId), cookies);
}
- if (method === 'Network.responseReceivedExtraInfo' && params) {
+ if (method === 'Network.responseReceivedExtraInfo') {
const responseParams =
params as Protocol.Network.ResponseReceivedExtraInfoEvent;
+ const {
+ headers,
+ blockedCookies,
+ requestId,
+ cookiePartitionKey = '',
+ exemptedCookies = [],
+ } = responseParams;
+
// Sometimes CDP gives "set-cookie" and sometimes it gives "Set-Cookie".
- if (
- !responseParams.headers['set-cookie'] &&
- !responseParams.headers['Set-Cookie']
- ) {
+ if (!headers['set-cookie'] && !headers['Set-Cookie']) {
return;
}
const cookies: CookieData[] = parseResponseReceivedExtraInfo(
- responseParams,
+ headers,
+ blockedCookies,
+ exemptedCookies,
+ cookiePartitionKey,
requestIdToCDPURLMapping[tabId],
url ?? '',
- cookieDB ?? {}
+ cookieDB ?? {},
+ requestId
);
+ if (cookies.length === 0) {
+ return;
+ }
+
syncCookieStore?.update(Number(tabId), cookies);
}
if (method === 'Audits.issueAdded' && params) {
const auditParams = params as Protocol.Audits.IssueAddedEvent;
const { code, details } = auditParams.issue;
-
if (code !== 'CookieIssue' && !details.cookieIssueDetails) {
return;
}
@@ -508,8 +465,9 @@ chrome.debugger.onEvent.addListener((source, method, params) => {
? cookie.domain.slice(1)
: cookie?.domain;
- // Adding alternate domains here because our extension calculates domain differently that the application tab.
- // This is done to capture both NID.google.com/ and NIDgoogle.com/ so that if we find either of the cookie we add issues to the cookie object
+ if (!cookie?.name || !domainToUse) {
+ return;
+ }
try {
syncCookieStore?.addCookieExclusionWarningReason(
cookie?.name + domainToUse + cookie?.path,
@@ -533,6 +491,7 @@ const listenToNewTab = async (tabId?: number) => {
if (tabMode && tabMode !== 'unlimited') {
const storedTabData = Object.keys(syncCookieStore?.tabsData ?? {});
+
await Promise.all(
storedTabData.map(async (tabIdToDelete) => {
syncCookieStore?.removeTabData(Number(tabIdToDelete));
@@ -569,146 +528,169 @@ const listenToNewTab = async (tabId?: number) => {
*/
// eslint-disable-next-line complexity
chrome.runtime.onMessage.addListener(async (request) => {
- if (
- request?.type === 'DevTools::ServiceWorker::SET_TAB_TO_READ' ||
- request?.type === 'Popup::ServiceWorker::SET_TAB_TO_READ'
- ) {
- const newTab = await listenToNewTab(request?.payload?.tabId);
+ if (!request.type) {
+ return;
+ }
+ const incomingMessageType = request.type;
+
+ if (SET_TAB_TO_READ === incomingMessageType) {
+ tabToRead = request?.payload?.tabId?.toString();
+ const newTab = await listenToNewTab(request?.payload?.tabId);
// Can't use sendResponse as delay is too long. So using sendMessage instead.
chrome.runtime.sendMessage({
- type: 'ServiceWorker::SET_TAB_TO_READ',
+ type: SET_TAB_TO_READ,
payload: {
- tabId: newTab,
+ tabId: Number(newTab),
},
});
- await chrome.tabs.reload(Number(newTab), { bypassCache: true });
+ if (globalIsUsingCDP) {
+ try {
+ if (globalIsUsingCDP) {
+ await chrome.debugger.attach({ tabId: Number(newTab) }, '1.3');
+ await chrome.debugger.sendCommand(
+ { tabId: Number(newTab) },
+ 'Network.enable'
+ );
+ await chrome.debugger.sendCommand(
+ { tabId: Number(newTab) },
+ 'Audits.enable'
+ );
+ } else {
+ await chrome.debugger.detach({ tabId: Number(newTab) });
+ }
+ } catch (error) {
+ //Fail silently
+ }
+ }
+
+ await reloadCurrentTab(Number(newTab));
}
- if (
- request?.type === 'DevTools::ServiceWorker::DEVTOOLS_STATE_OPEN' &&
- request?.payload?.tabId
- ) {
- const dataToSend: { [key: string]: string } = {};
+ if (SERVICE_WORKER_TABS_RELOAD_COMMAND === incomingMessageType) {
+ const sessionStorage = await chrome.storage.session.get();
+ if (Object.keys(sessionStorage).includes('allowedNumberOfTabs')) {
+ tabMode = sessionStorage.allowedNumberOfTabs;
+ }
+
+ if (Object.keys(sessionStorage).includes('isUsingCDP')) {
+ globalIsUsingCDP = sessionStorage.isUsingCDP;
+ }
+
+ await chrome.storage.session.remove(['allowedNumberOfTabs', 'isUsingCDP']);
+
+ await chrome.storage.session.set({
+ pendingReload: false,
+ });
+
+ await chrome.storage.sync.set({
+ allowedNumberOfTabs: tabMode,
+ isUsingCDP: globalIsUsingCDP,
+ });
+
+ const tabs = await chrome.tabs.query({});
+
+ await Promise.all(
+ tabs.map(async ({ id }) => {
+ if (!id) {
+ return;
+ }
+ try {
+ if (globalIsUsingCDP) {
+ await chrome.debugger.attach({ tabId: id }, '1.3');
+ await chrome.debugger.sendCommand({ tabId: id }, 'Network.enable');
+ await chrome.debugger.sendCommand({ tabId: id }, 'Audits.enable');
+ } else {
+ await chrome.debugger.detach({ tabId: id });
+ }
+ } catch (error) {
+ //Fail silently
+ }
+ resetCookieBadgeText(id);
+ await reloadCurrentTab(id);
+ })
+ );
+
+ await chrome.runtime.sendMessage({
+ type: SERVICE_WORKER_RELOAD_MESSAGE,
+ });
+ }
+
+ if (!request?.payload?.tabId) {
+ return;
+ }
+
+ const incomingMessageTabId = request.payload.tabId;
+
+ if (DEVTOOLS_OPEN === incomingMessageType) {
+ const dataToSend: { [key: string]: string | boolean } = {};
dataToSend['tabMode'] = tabMode;
if (tabMode === 'single') {
dataToSend['tabToRead'] = tabToRead;
}
- chrome.runtime.sendMessage({
- type: 'ServiceWorker::DevTools::INITIAL_SYNC',
- payload: dataToSend,
- });
if (
- !syncCookieStore?.tabs[request.payload.tabId] &&
+ !syncCookieStore?.tabs[incomingMessageTabId] &&
tabMode === 'unlimited'
) {
- const currentTab = await getTab(request.payload.tabId);
-
- syncCookieStore?.addTabData(request?.payload?.tabId);
- syncCookieStore?.updateUrl(
- request?.payload?.tabId,
- currentTab?.url || ''
- );
+ const currentTab = await getTab(incomingMessageTabId);
+ dataToSend['psatOpenedAfterPageLoad'] = request.payload.doNotReReload
+ ? false
+ : true;
+ syncCookieStore?.addTabData(incomingMessageTabId);
+ syncCookieStore?.updateUrl(incomingMessageTabId, currentTab?.url || '');
}
- syncCookieStore?.updateDevToolsState(request?.payload?.tabId, true);
+ chrome.runtime.sendMessage({
+ type: INITIAL_SYNC,
+ payload: dataToSend,
+ });
+
+ syncCookieStore?.updateDevToolsState(incomingMessageTabId, true);
- if (syncCookieStore?.tabsData[request.payload.tabId]) {
+ if (syncCookieStore?.tabsData[incomingMessageTabId]) {
syncCookieStore?.sendUpdatedDataToPopupAndDevTools(
- request.payload.tabId,
+ incomingMessageTabId,
true
);
}
}
- if (
- request?.type === 'Popup::ServiceWorker::POPUP_STATE_OPEN' &&
- request?.payload?.tabId
- ) {
+ if (POPUP_OPEN === incomingMessageType) {
const dataToSend: { [key: string]: string } = {};
dataToSend['tabMode'] = tabMode;
if (tabMode === 'single') {
dataToSend['tabToRead'] = tabToRead;
}
+
chrome.runtime.sendMessage({
- type: 'ServiceWorker::Popup::INITIAL_SYNC',
+ type: INITIAL_SYNC,
payload: dataToSend,
});
- syncCookieStore?.updatePopUpState(request?.payload?.tabId, true);
+ syncCookieStore?.updatePopUpState(incomingMessageTabId, true);
- if (syncCookieStore?.tabsData[request?.payload?.tabId]) {
+ if (syncCookieStore?.tabsData[incomingMessageTabId]) {
syncCookieStore?.sendUpdatedDataToPopupAndDevTools(
- request?.payload?.tabId,
+ incomingMessageTabId,
true
);
}
}
- if (
- request?.type === 'DevTools::ServiceWorker::DEVTOOLS_STATE_CLOSE' &&
- request?.payload?.tabId
- ) {
- syncCookieStore?.updateDevToolsState(request?.payload?.tabId, false);
+ if (DEVTOOLS_CLOSE === incomingMessageType) {
+ syncCookieStore?.updateDevToolsState(incomingMessageTabId, false);
}
- if (
- request?.type === 'Popup::ServiceWorker::POPUP_STATE_CLOSE' &&
- request?.payload?.tabId
- ) {
- syncCookieStore?.updatePopUpState(request?.payload?.tabId, false);
+ if (POPUP_CLOSE === incomingMessageType) {
+ syncCookieStore?.updatePopUpState(incomingMessageTabId, false);
}
- if (
- request?.type === 'DevTools::ServiceWorker::SET_JAVASCRIPT_COOKIE' &&
- request?.payload?.tabId
- ) {
- syncCookieStore?.update(
- request?.payload?.tabId,
- request?.payload?.cookieData
- );
- }
-
- if (
- request?.type === 'DevTools::ServiceWorker::RELOAD_ALL_TABS' ||
- request?.type === 'Popup::ServiceWorker::RELOAD_ALL_TABS'
- ) {
- const sessionStorage = await chrome.storage.session.get();
- if (Object.keys(sessionStorage).includes('allowedNumberOfTabs')) {
- tabMode = sessionStorage.allowedNumberOfTabs;
- }
-
- if (Object.keys(sessionStorage).includes('isUsingCDP')) {
- globalIsUsingCDP = sessionStorage.isUsingCDP;
- }
-
- await chrome.storage.session.remove(['allowedNumberOfTabs', 'isUsingCDP']);
- await chrome.storage.session.set({
- pendingReload: false,
- });
-
- await chrome.storage.sync.set({
- allowedNumberOfTabs: tabMode,
- isUsingCDP: globalIsUsingCDP,
- });
-
- await chrome.runtime.sendMessage({
- type: 'ServiceWorker::DevTools::TABS_RELOADED',
- });
-
- const tabs = await chrome.tabs.query({});
- await Promise.all(
- tabs.map(async (tab) => {
- if (!tab.id) {
- return;
- }
- await reloadCurrentTab(tab.id);
- })
- );
+ if (DEVTOOLS_SET_JAVASCSCRIPT_COOKIE === incomingMessageType) {
+ syncCookieStore?.update(incomingMessageTabId, request?.payload?.cookieData);
}
});
@@ -746,53 +728,41 @@ chrome.storage.sync.onChanged.addListener(
if (changes?.allowedNumberOfTabs?.newValue === 'single') {
tabToRead = '';
-
- chrome.runtime.sendMessage({
- type: 'ServiceWorker::DevTools::INITIAL_SYNC',
- payload: {
- tabMode,
- tabToRead: tabToRead,
- },
- });
-
- chrome.runtime.sendMessage({
- type: 'ServiceWorker::Popup::INITIAL_SYNC',
- payload: {
- tabMode,
- tabToRead: tabToRead,
- },
- });
+ try {
+ await chrome.runtime.sendMessage({
+ type: INITIAL_SYNC,
+ payload: {
+ tabMode,
+ tabToRead: tabToRead,
+ },
+ });
+ } catch (error) {
+ //Fail silently
+ }
tabs.map((tab) => {
if (!tab?.id) {
return tab;
}
- chrome.action.setBadgeText({
- tabId: tab?.id,
- text: '',
- });
+ resetCookieBadgeText(tab.id);
syncCookieStore?.removeTabData(tab.id);
return tab;
});
} else {
- chrome.runtime.sendMessage({
- type: 'ServiceWorker::Popup::INITIAL_SYNC',
- payload: {
- tabMode,
- tabToRead: tabToRead,
- },
- });
-
- chrome.runtime.sendMessage({
- type: 'ServiceWorker::DevTools::INITIAL_SYNC',
- payload: {
- tabMode,
- tabToRead: tabToRead,
- },
- });
+ try {
+ await chrome.runtime.sendMessage({
+ type: INITIAL_SYNC,
+ payload: {
+ tabMode,
+ tabToRead: tabToRead,
+ },
+ });
+ } catch (error) {
+ //Fail silently
+ }
tabs.forEach((tab) => {
if (!tab?.id) {
@@ -818,32 +788,18 @@ chrome.storage.sync.onChanged.addListener(
globalIsUsingCDP = changes?.isUsingCDP?.newValue;
- chrome.runtime.sendMessage({
- type: 'ServiceWorker::Popup::CHANGE_CDP_SETTING',
- payload: {
- isUsingCDP: changes?.isUsingCDP?.newValue,
- },
- });
-
- chrome.runtime.sendMessage({
- type: 'ServiceWorker::DevTools::CHANGE_CDP_SETTING',
- payload: {
- isUsingCDP: changes?.isUsingCDP?.newValue,
- },
- });
-
const tabs = await chrome.tabs.query({});
if (!changes?.isUsingCDP?.newValue) {
await Promise.all(
- tabs.map(async (tab) => {
- if (!tab.id) {
+ tabs.map(async ({ id }) => {
+ if (!id) {
return;
}
try {
- await chrome.debugger.detach({ tabId: tab.id });
- syncCookieStore?.sendUpdatedDataToPopupAndDevTools(tab.id);
+ await chrome.debugger.detach({ tabId: id });
+ syncCookieStore?.sendUpdatedDataToPopupAndDevTools(id);
} catch (error) {
// eslint-disable-next-line no-console
console.warn(error);
@@ -851,12 +807,12 @@ chrome.storage.sync.onChanged.addListener(
})
);
} else {
- tabs.forEach((tab) => {
- if (!tab.id) {
+ tabs.forEach(({ id }) => {
+ if (!id) {
return;
}
- syncCookieStore?.sendUpdatedDataToPopupAndDevTools(tab.id);
+ syncCookieStore?.sendUpdatedDataToPopupAndDevTools(id);
});
}
}
diff --git a/packages/extension/src/serviceWorker/parseResponseCookieHeader.ts b/packages/extension/src/serviceWorker/parseResponseCookieHeader.ts
index b7bb87ee6..6924b4f82 100644
--- a/packages/extension/src/serviceWorker/parseResponseCookieHeader.ts
+++ b/packages/extension/src/serviceWorker/parseResponseCookieHeader.ts
@@ -43,6 +43,7 @@ import { createCookieObject } from './createCookieObject';
* @param {number} frameId Id of a frame in which this cookie is used.
* @param {Protocol.Network.Cookie[]} cdpCookiesList List cookies from the request.
* @param {string} requestId Request id.
+ * @param {boolean} globalIsUsingCDP Boolean to determie whether or not CDP is being used.
* @returns {CookieData} Parsed cookie object.
*/
const parseResponseCookieHeader = (
@@ -52,7 +53,8 @@ const parseResponseCookieHeader = (
tabUrl: string,
frameId: number,
cdpCookiesList: Protocol.Network.Cookie[],
- requestId: string
+ requestId: string,
+ globalIsUsingCDP: boolean
): CookieData => {
let parsedCookie: CookieData['parsedCookie'] = cookie.parse(value);
@@ -98,7 +100,11 @@ const parseResponseCookieHeader = (
type: RESPONSE_EVENT.CHROME_WEBREQUEST_ON_RESPONSE_STARTED,
requestId,
url: url,
- blocked: isExpired ? false : !isFoundInCDPCookieList,
+ blocked: globalIsUsingCDP
+ ? isExpired
+ ? false
+ : !isFoundInCDPCookieList
+ : false,
timeStamp: Date.now(),
},
],
diff --git a/packages/extension/src/store/synchnorousCookieStore.ts b/packages/extension/src/store/synchnorousCookieStore.ts
index 444568d2d..920e95774 100644
--- a/packages/extension/src/store/synchnorousCookieStore.ts
+++ b/packages/extension/src/store/synchnorousCookieStore.ts
@@ -28,6 +28,7 @@ import type { Protocol } from 'devtools-protocol';
*/
import updateCookieBadgeText from './utils/updateCookieBadgeText';
import { deriveBlockingStatus } from './utils/deriveBlockingStatus';
+import { NEW_COOKIE_DATA } from '../constants';
class SynchnorousCookieStore {
/**
@@ -137,6 +138,9 @@ class SynchnorousCookieStore {
? this.tabsData[tabId][cookieKey].headerType
: cookie.headerType,
frameIdList,
+ exemptionReason:
+ cookie?.exemptionReason ||
+ this.tabsData[tabId][cookieKey]?.exemptionReason,
};
} else {
this.tabs[tabId].newUpdates++;
@@ -235,8 +239,6 @@ class SynchnorousCookieStore {
if (!this.tabsData[tabId]) {
return;
}
-
- // Check if primaryDomain cookie exists
if (this.tabsData[tabId] && this.tabsData[tabId][cookieName]) {
this.tabsData[tabId][cookieName].blockedReasons = [
...new Set([
@@ -244,7 +246,6 @@ class SynchnorousCookieStore {
...exclusionReasons,
]),
];
-
this.tabsData[tabId][cookieName].warningReasons = [
...new Set([
...(this.tabsData[tabId][cookieName].warningReasons ?? []),
@@ -255,7 +256,6 @@ class SynchnorousCookieStore {
this.tabsData[tabId][cookieName].isBlocked =
exclusionReasons.length > 0 ? true : false;
this.tabs[tabId].newUpdates++;
- // Check if secondaryDomain cookie exists
} else {
this.tabs[tabId].newUpdates++;
// If none of them exists. This case is possible when the cookies hasnt processed and we already have an issue.
@@ -349,27 +349,14 @@ class SynchnorousCookieStore {
try {
if (
- this.tabs[tabId].devToolsOpenState &&
- (overrideForInitialSync || this.tabs[tabId].newUpdates > 0)
+ this.tabs[tabId].devToolsOpenState ||
+ (this.tabs[tabId].popupOpenState &&
+ (overrideForInitialSync || this.tabs[tabId].newUpdates > 0))
) {
sentMessageAnyWhere = true;
await chrome.runtime.sendMessage({
- type: 'ServiceWorker::DevTools::NEW_COOKIE_DATA',
- payload: {
- tabId,
- cookieData: this.tabsData[tabId],
- },
- });
- }
-
- if (
- this.tabs[tabId].popupOpenState &&
- (overrideForInitialSync || this.tabs[tabId].newUpdates > 0)
- ) {
- sentMessageAnyWhere = true;
- await chrome.runtime.sendMessage({
- type: 'ServiceWorker::Popup::NEW_COOKIE_DATA',
+ type: NEW_COOKIE_DATA,
payload: {
tabId,
cookieData: this.tabsData[tabId],
diff --git a/packages/extension/src/store/utils/deriveBlockingStatus.ts b/packages/extension/src/store/utils/deriveBlockingStatus.ts
index 4e2c7b98c..edc45b5b7 100644
--- a/packages/extension/src/store/utils/deriveBlockingStatus.ts
+++ b/packages/extension/src/store/utils/deriveBlockingStatus.ts
@@ -34,10 +34,12 @@ import {
*/
function deriveInboundBlocking(respEvents: responsEvent[]): BLOCK_STATUS {
// if there are not response events the cookie must be stored in a previous visit
+ // Or there is a javascript not used in the request header.
if (respEvents.length === 0) {
return BLOCK_STATUS.NOT_BLOCKED;
}
+ // Number of responses in which the cookie was blocked.
const numBlocked: number = respEvents.reduce((acc, event) => {
if (event.blocked) {
return acc + 1;
diff --git a/packages/extension/src/utils/isSingleTabProcessingMode.ts b/packages/extension/src/store/utils/resetCookieBadgeText.ts
similarity index 62%
rename from packages/extension/src/utils/isSingleTabProcessingMode.ts
rename to packages/extension/src/store/utils/resetCookieBadgeText.ts
index 729ff2a6f..595ffa2b7 100644
--- a/packages/extension/src/utils/isSingleTabProcessingMode.ts
+++ b/packages/extension/src/store/utils/resetCookieBadgeText.ts
@@ -14,13 +14,15 @@
* limitations under the License.
*/
/**
- * This determines the processing mode of the extension True if singleTabProcessingMode false if multiple tab being processed.
- * @returns boolean.
+ * Resets the extension badge text.
+ * @param {number} tabId Tab id where the badge text has to be reset.
*/
-export default async function isSingleTabProcessingMode() {
- const syncStorage = await chrome.storage.sync.get();
- return (
- syncStorage.allowedNumberOfTabs &&
- syncStorage.allowedNumberOfTabs !== 'unlimited'
- );
+export default function resetCookieBadgeText(tabId: number) {
+ if (!tabId) {
+ return;
+ }
+ chrome.action.setBadgeText({
+ tabId: tabId,
+ text: '',
+ });
}
diff --git a/packages/extension/src/store/utils/updateCookieBadgeText.ts b/packages/extension/src/store/utils/updateCookieBadgeText.ts
index 3aa3aebeb..0ce8c13c0 100644
--- a/packages/extension/src/store/utils/updateCookieBadgeText.ts
+++ b/packages/extension/src/store/utils/updateCookieBadgeText.ts
@@ -32,11 +32,13 @@ export default function updateCookieBadgeText(
if (!tabId) {
return;
}
+
const numCookies = Object.keys(storage).filter(
(cookieKey) =>
storage[cookieKey]?.parsedCookie &&
storage[cookieKey].frameIdList?.length >= 0
).length;
+
if (numCookies >= 0) {
chrome.action.setBadgeText(
{
diff --git a/packages/extension/src/utils/canProcessCookies.ts b/packages/extension/src/utils/canProcessCookies.ts
index ab4d16c9e..af2504712 100644
--- a/packages/extension/src/utils/canProcessCookies.ts
+++ b/packages/extension/src/utils/canProcessCookies.ts
@@ -19,7 +19,7 @@
* @param {string | null | undefined} tabUrl Current tab url.
* @param {string} tabToRead The current tab being read y extension in case of single processing mode.
* @param {number} currentTabId The tabId of the current request is associated to.
- * @param {chrome.webRequest.WebResponseHeadersDetails['responseHeaders']} responseHeaders The tabId of the current request is associated to.
+ * @param {chrome.webRequest.HttpHeader[] | undefined} headers The tabId of the current request is associated to.
* @returns {boolean}.
*/
export default function canProcessCookies(
@@ -27,9 +27,9 @@ export default function canProcessCookies(
tabUrl: string | null | undefined,
tabToRead: string,
currentTabId: number,
- responseHeaders: chrome.webRequest.WebResponseHeadersDetails['responseHeaders']
+ headers: chrome.webRequest.HttpHeader[] | undefined
) {
- if (!tabUrl || !responseHeaders || tabUrl === 'chrome://newtab/') {
+ if (!tabUrl || !headers || tabUrl === 'chrome://newtab/') {
return false;
}
diff --git a/packages/extension/src/utils/downloadReport.ts b/packages/extension/src/utils/downloadReport.ts
new file mode 100644
index 000000000..f1fbb441a
--- /dev/null
+++ b/packages/extension/src/utils/downloadReport.ts
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import type {
+ LibraryData,
+ TabCookies,
+ TabFrames,
+} from '@ps-analysis-tool/common';
+import { saveAs } from 'file-saver';
+/**
+ * Internal dependencies.
+ */
+import generateReportObject from './generateReportObject';
+
+/**
+ * Utility function to download report.
+ * @param url Top level URL.
+ * @param tabCookies Tab cookies.
+ * @param tabFrames Tab frames.
+ * @param libraryMatches
+ */
+export default async function downloadReport(
+ url: string,
+ tabCookies: TabCookies,
+ tabFrames: TabFrames,
+ libraryMatches: LibraryData
+) {
+ const htmlText = await (await fetch('../report/index.html')).text();
+ const parser = new DOMParser();
+ const reportDom = parser.parseFromString(htmlText, 'text/html');
+
+ // Injections
+ const script = reportDom.createElement('script');
+
+ const reportData = generateReportObject(
+ tabCookies,
+ tabFrames,
+ libraryMatches
+ );
+
+ const code = `window.PSAT_DATA = ${JSON.stringify(reportData)}`;
+
+ script.text = code;
+ reportDom.head.appendChild(script);
+
+ const injectedHtmlText = `${reportDom.head.innerHTML}${reportDom.body.innerHTML}`;
+ const html = new Blob([injectedHtmlText]);
+ const hostname = new URL(url).hostname;
+
+ saveAs(html, `${hostname.replace('.', '-')}-report.html`);
+}
diff --git a/packages/extension/src/utils/generateReportObject.ts b/packages/extension/src/utils/generateReportObject.ts
new file mode 100644
index 000000000..461947bcf
--- /dev/null
+++ b/packages/extension/src/utils/generateReportObject.ts
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import type {
+ LibraryData,
+ TabCookies,
+ TabFrames,
+} from '@ps-analysis-tool/common';
+
+import {
+ prepareCookieStatsComponents,
+ prepareCookiesCount,
+ prepareFrameStatsComponent,
+ type DataMapping,
+} from '@ps-analysis-tool/design-system';
+
+/**
+ * Utility function to generate report object.
+ * @param url Top level URL.
+ * @param tabCookies Tab cookies.
+ * @param tabFrames Tab frames.
+ * @param libraryMatches
+ */
+export default function generateReportObject(
+ tabCookies: TabCookies,
+ tabFrames: TabFrames,
+ libraryMatches: LibraryData
+) {
+ const cookieStats = prepareCookiesCount(tabCookies);
+ const cookiesStatsComponents = prepareCookieStatsComponents(cookieStats);
+ const frameStateCreator = prepareFrameStatsComponent(tabFrames, tabCookies);
+
+ const cookieClassificationDataMapping: DataMapping[] = [
+ {
+ title: 'Total cookies',
+ count: cookieStats.total,
+ data: cookiesStatsComponents.legend,
+ },
+ {
+ title: '1st party cookies',
+ count: cookieStats.firstParty.total,
+ data: cookiesStatsComponents.firstParty,
+ },
+ {
+ title: '3rd party cookies',
+ count: cookieStats.thirdParty.total,
+ data: cookiesStatsComponents.thirdParty,
+ },
+ ];
+
+ const blockedCookieDataMapping: DataMapping[] = [
+ {
+ title: 'Blocked cookies',
+ count: cookieStats.blockedCookies.total,
+ data: cookiesStatsComponents.blocked,
+ },
+ ];
+
+ const exemptedCookiesDataMapping: DataMapping[] = [
+ {
+ title: 'Exempted cookies',
+ count: cookieStats.exemptedCookies.total,
+ data: cookiesStatsComponents.exempted,
+ },
+ ];
+
+ return {
+ cookieClassificationDataMapping,
+ tabCookies,
+ cookiesStatsComponents,
+ tabFrames,
+ showInfoIcon: true,
+ showHorizontalMatrix: false,
+ blockedCookieDataMapping,
+ showBlockedInfoIcon: true,
+ frameStateCreator,
+ libraryMatches,
+ exemptedCookiesDataMapping,
+ };
+}
diff --git a/packages/extension/src/utils/getFramesForCurrentTab.ts b/packages/extension/src/utils/getFramesForCurrentTab.ts
new file mode 100644
index 000000000..ba9d02427
--- /dev/null
+++ b/packages/extension/src/utils/getFramesForCurrentTab.ts
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import type { TabFrames } from '@ps-analysis-tool/common';
+/**
+ * Internal dependencies
+ */
+import { isOnRWS } from '../contentScript/utils';
+
+/**
+ * This function returns tab frames state for frame ids and frame URLs along with rws information from using chrome.webNavigation.getAllFrames.
+ * @returns {TabFrames|null} Tabframes and related details if available else null.
+ */
+export default async function getFramesForCurrentTab() {
+ const tabId = chrome.devtools.inspectedWindow.tabId;
+ if (!tabId) {
+ return null;
+ }
+
+ const regexForFrameUrl =
+ /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:/\n?]+)/;
+
+ const currentTabFrames = await chrome.webNavigation.getAllFrames({
+ tabId,
+ });
+ const modifiedTabFrames: TabFrames = {};
+
+ currentTabFrames?.forEach(({ url, frameId, frameType }) => {
+ if (url && url.includes('http')) {
+ const parsedUrl = regexForFrameUrl.exec(url);
+ if (parsedUrl && parsedUrl[0]) {
+ if (modifiedTabFrames[parsedUrl[0]]) {
+ modifiedTabFrames[parsedUrl[0]].frameIds.push(frameId);
+ } else {
+ modifiedTabFrames[parsedUrl[0]] = {
+ frameIds: [frameId],
+ frameType,
+ };
+ }
+ }
+ }
+ });
+ await Promise.all(
+ Object.keys(modifiedTabFrames).map(async (tabFrame) => {
+ modifiedTabFrames[tabFrame].isOnRWS = await isOnRWS(tabFrame);
+ return tabFrame;
+ })
+ );
+
+ return modifiedTabFrames;
+}
diff --git a/packages/extension/src/serviceWorker/isValidURL.ts b/packages/extension/src/utils/isValidURL.ts
similarity index 100%
rename from packages/extension/src/serviceWorker/isValidURL.ts
rename to packages/extension/src/utils/isValidURL.ts
diff --git a/packages/extension/src/utils/parseHeaders.ts b/packages/extension/src/utils/parseHeaders.ts
new file mode 100644
index 000000000..cc80bb82a
--- /dev/null
+++ b/packages/extension/src/utils/parseHeaders.ts
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import { Protocol } from 'devtools-protocol';
+import { type CookieData, type CookieDatabase } from '@ps-analysis-tool/common';
+import parseResponseCookieHeader from '../serviceWorker/parseResponseCookieHeader';
+import canProcessCookies from './canProcessCookies';
+import parseRequestCookieHeader from '../serviceWorker/parseRequestCookieHeader';
+
+type CDPCookiesType = { [cookies: string]: Protocol.Network.Cookie[] };
+/**
+ * Common utility function that can parse both request and response headers.
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
+ * @param {boolean} globalIsUsingCDP Boolean to determie whether or not CDP is being used.
+ * @param {string} type The type of headers that are to be processed.
+ * @param {string} tabToRead The current tab being read in single tab mode.
+ * @param {string} tabMode The processing mode of the extension.
+ * @param {string} tabId The tabId of the current request.
+ * @param {string} url Cookie URL (URL of the server which is setting/updating cookies).
+ * @param {CookieDatabase} cookieDB Dictionary from open cookie database
+ * @param {string | null | undefined} tabUrl top url of the tab from which the request originated.
+ * @param {number} frameId Id of the frame the cookie is used in.
+ * @param {string} requestId Request id.
+ * @param {chrome.webRequest.HttpHeader} headers The headers that need to be parsed to get cookies.
+ * @returns {CookieData[] | null} returns set of cookies from the header.
+ */
+export default async function parseHeaders(
+ globalIsUsingCDP: boolean,
+ type: 'request' | 'response',
+ tabToRead: string,
+ tabMode: 'single' | 'unlimited',
+ tabId: number,
+ url: string,
+ cookieDB: CookieDatabase,
+ tabUrl: string | null | undefined,
+ frameId: number,
+ requestId: string,
+ headers?: chrome.webRequest.HttpHeader[]
+) {
+ if (!canProcessCookies(tabMode, tabUrl, tabToRead, tabId, headers)) {
+ return null;
+ }
+
+ let cdpCookies: CDPCookiesType;
+
+ if (globalIsUsingCDP) {
+ try {
+ // Since we are using CDP we might as well use it to get the proper cookies in the request this will further reduce the load of domain calculation
+ cdpCookies = (await chrome.debugger.sendCommand(
+ { tabId: tabId },
+ 'Network.getCookies',
+ { urls: [url] }
+ )) as CDPCookiesType;
+ } catch (error) {
+ //Fail silently
+ }
+ }
+
+ switch (type) {
+ case 'response':
+ return headers?.reduce((accumulator, header) => {
+ if (
+ header.name.toLowerCase() === 'set-cookie' &&
+ header.value &&
+ tabUrl &&
+ cookieDB
+ ) {
+ const cookie = parseResponseCookieHeader(
+ url,
+ header.value,
+ cookieDB,
+ tabUrl,
+ frameId,
+ cdpCookies?.cookies ?? [],
+ requestId,
+ globalIsUsingCDP
+ );
+
+ return [...accumulator, cookie];
+ }
+
+ return accumulator;
+ }, []);
+
+ case 'request':
+ return headers?.reduce((accumulator, header) => {
+ if (
+ header.name.toLowerCase() === 'cookie' &&
+ header.value &&
+ url &&
+ tabUrl &&
+ cookieDB
+ ) {
+ const cookieList = parseRequestCookieHeader(
+ url,
+ header.value,
+ cookieDB,
+ tabUrl,
+ frameId,
+ cdpCookies?.cookies ?? [],
+ requestId
+ );
+
+ return [...accumulator, ...cookieList];
+ }
+
+ return accumulator;
+ }, []);
+ default:
+ return [];
+ }
+}
diff --git a/packages/extension/src/utils/processAndStoreDocumentCookies.ts b/packages/extension/src/utils/processAndStoreDocumentCookies.ts
index 65903ae82..9938e2d8d 100644
--- a/packages/extension/src/utils/processAndStoreDocumentCookies.ts
+++ b/packages/extension/src/utils/processAndStoreDocumentCookies.ts
@@ -28,6 +28,7 @@ import { type Cookie as ParsedCookie } from 'simple-cookie';
*/
import { createCookieObject } from '../serviceWorker/createCookieObject';
import { fetchDictionary } from './fetchCookieDictionary';
+import { GET_JS_COOKIES } from '../constants';
interface ProcessAndStoreDucmentCookies {
tabUrl: string;
@@ -53,6 +54,8 @@ const processAndStoreDocumentCookies = async ({
parsedCookie.domain = singleCookie.domain?.startsWith('.')
? singleCookie.domain
: '.' + singleCookie.domain;
+ } else {
+ parsedCookie.domain = window.location.hostname;
}
parsedCookie = createCookieObject(
@@ -86,7 +89,7 @@ const processAndStoreDocumentCookies = async ({
);
await chrome.runtime.sendMessage({
- type: 'DevTools::ServiceWorker::SET_JAVASCRIPT_COOKIE',
+ type: GET_JS_COOKIES,
payload: {
tabId,
cookieData: parsedCookieData,
diff --git a/packages/extension/src/utils/reloadCurrentTab.ts b/packages/extension/src/utils/reloadCurrentTab.ts
index 2dba619cb..b6854a996 100644
--- a/packages/extension/src/utils/reloadCurrentTab.ts
+++ b/packages/extension/src/utils/reloadCurrentTab.ts
@@ -25,7 +25,7 @@ const reloadCurrentTab = async (tabId: number | undefined = undefined) => {
const _currentTabId = Number(currentTabId);
if (_currentTabId) {
- chrome.tabs.reload(_currentTabId);
+ chrome.tabs.reload(_currentTabId, { bypassCache: true });
}
};
diff --git a/packages/extension/src/utils/test-data/cookieMockData.ts b/packages/extension/src/utils/test-data/cookieMockData.ts
index 818c38278..80652a7e3 100644
--- a/packages/extension/src/utils/test-data/cookieMockData.ts
+++ b/packages/extension/src/utils/test-data/cookieMockData.ts
@@ -21,7 +21,7 @@ import { emptyAnalytics } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import type { CookieStoreContext } from '../../view/devtools/stateProviders/syncCookieStore';
+import { type CookieStoreContext } from '../../view/devtools/stateProviders/cookie';
const emptyCookie = {
name: '',
diff --git a/packages/extension/src/utils/test-data/tabFrames.ts b/packages/extension/src/utils/test-data/tabFrames.ts
new file mode 100644
index 000000000..a41d81947
--- /dev/null
+++ b/packages/extension/src/utils/test-data/tabFrames.ts
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+const tabFrames = [
+ {
+ processId: 1,
+ frameId: 0,
+ url: 'https://edition.cnn.com',
+ documentId: '40245632AWDER',
+ documentLifecycle: 'active',
+ errorOccurred: false,
+ frameType: 'outermost_frame',
+ parentFrameId: 0,
+ },
+ {
+ processId: 1,
+ frameId: 2,
+ url: 'https://crxd.net',
+ documentId: '40245632WADER',
+ documentLifecycle: 'active',
+ errorOccurred: false,
+ frameType: 'sub_frame',
+ parentFrameId: 0,
+ },
+ {
+ processId: 1,
+ frameId: 3,
+ url: 'https://edition.cnn.com',
+ documentId: '40245632AWDER',
+ documentLifecycle: 'active',
+ errorOccurred: false,
+ frameType: 'outermost_frame',
+ parentFrameId: 0,
+ },
+];
+export default tabFrames;
diff --git a/packages/extension/src/utils/tests/data.mock.ts b/packages/extension/src/utils/tests/data.mock.ts
new file mode 100644
index 000000000..db2b00351
--- /dev/null
+++ b/packages/extension/src/utils/tests/data.mock.ts
@@ -0,0 +1,7455 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const tabCookies = {
+ '_gcl_aurtcamp.com/': {
+ parsedCookie: {
+ name: '_gcl_au',
+ value: '1.1.1643004070.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2024-07-02T05:40:12.000Z',
+ partitionKey: '',
+ size: 32,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: 'Google',
+ category: 'Marketing',
+ name: '_gcl_au',
+ domain: '',
+ description:
+ 'Used by Google AdSense for experimenting with advertisement efficiency across websites using their services.',
+ retention: '3 months',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838658,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838663,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838679,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838685,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838694,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838713,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838838,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839204,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839623,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893820,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_user_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_user_id',
+ value: 'null',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 15,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_user_id',
+ domain: '.trustpilot.com',
+ description:
+ ' This cookie helps track visitor usage, events, target marketing, and can also measure application performance and stability.',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838679,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838685,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838694,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838715,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838839,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893820,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_group_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_group_id',
+ value: 'null',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 16,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_group_id',
+ domain: '.trustpilot.com',
+ description: 'Track visitor usage and events within the website',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838679,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838686,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838695,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838810,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893820,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_anonymous_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_anonymous_id',
+ value: '%220eae481f-71ad-4118-9309-1f60ae8f9f6d%22',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 58,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_anonymous_id',
+ domain: '.trustpilot.com',
+ description:
+ 'Used for Analytics and help count how many people visit a certain site by tracking if you have visited before',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838680,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838686,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838695,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_gartcamp.com/': {
+ parsedCookie: {
+ name: '_ga',
+ value: 'GA1.1.1593307359.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-14T08:03:59.200Z',
+ partitionKey: '',
+ size: 30,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: '_ga',
+ domain: 'google-analytics.com (3rd party) or',
+ description: 'ID used to identify users',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838680,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838687,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838696,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893799,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896283,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'FPIDrtcamp.com/': {
+ parsedCookie: {
+ name: 'FPID',
+ value:
+ 'FPID2.2.BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: '',
+ expires: '2025-05-14T08:03:59.874Z',
+ partitionKey: '',
+ size: 71,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: 'FPID',
+ domain: '',
+ description:
+ "Registers statistical data on users' behaviour on the website. Used for internal analytics by the website operator.",
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838660,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838680,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838687,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838696,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839206,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839626,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893799,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896283,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839875,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839882,
+ },
+ ],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'FPAUrtcamp.com/': {
+ parsedCookie: {
+ name: 'FPAU',
+ value: '1.1.1643004070.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: '',
+ expires: '2024-07-02T05:40:11.874Z',
+ partitionKey: '',
+ size: 29,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Marketing',
+ name: 'FPAU',
+ domain: '',
+ description:
+ 'Assigns a specific ID to the visitor. This allows the website to determine the number of specific user-visits for analysis and statistics.',
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838660,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838665,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838672,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838681,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838688,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838696,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839206,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839626,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893799,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896283,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839876,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839882,
+ },
+ ],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'track_uidrtcamp.com/': {
+ parsedCookie: {
+ name: 'track_uid',
+ value: 'df985b92-a92b-7c79-35c7-3030565fd182',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-09T08:04:01.000Z',
+ partitionKey: '',
+ size: 45,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838661,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838665,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838669,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838673,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838682,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838688,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838697,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838841,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839206,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839626,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893800,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893822,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896284,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'stg_returning_visitorrtcamp.com/': {
+ parsedCookie: {
+ name: 'stg_returning_visitor',
+ value: 'Wed%2C%2003%20Apr%202024%2008:00:23%20GMT',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: 'strict',
+ expires: '2025-04-03T08:00:23.000Z',
+ partitionKey: '',
+ size: 62,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'Strict',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_returning_visitor',
+ domain: '',
+ description:
+ 'Determines if the visitor has already been to your website — they are returning visitors.',
+ retention: '365 days',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838661,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838669,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838673,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838682,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838689,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838698,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838826,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838841,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839621,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893800,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893822,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896284,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ '_parsely_visitorrtcamp.com/': {
+ parsedCookie: {
+ name: '_parsely_visitor',
+ value:
+ '{%22id%22:%22pid=55cc8d59-04cf-4bcd-aaca-5e6bb9ca7cc4%22%2C%22session_count%22:10%2C%22last_session_ts%22:1712649839162}',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-09T18:05:00.000Z',
+ partitionKey: false,
+ size: 136,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838661,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838669,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838674,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838683,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838690,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838699,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838826,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838844,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839207,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839629,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893802,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893823,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896285,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_pk_id.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59rtcamp.com/': {
+ parsedCookie: {
+ name: '_pk_id.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59',
+ value: 'e232543d43714eb7.1712122813.9.1712649896.1712649840.',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: 'lax',
+ expires: '2025-05-07T08:04:56.000Z',
+ partitionKey: '',
+ size: 100,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'lax',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ },
+ analytics: {
+ platform: 'Matomo',
+ category: 'Analytics',
+ name: '_pk_id*',
+ domain: '',
+ description:
+ 'Used to store a few details about the user such as the unique visitor ID',
+ retention: '13 months',
+ dataController: 'Matomo',
+ gdprUrl: 'https://matomo.org/privacy-policy/',
+ wildcard: '1',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838662,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838675,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838684,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838691,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838699,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838837,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838844,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839621,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893805,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896290,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ 'stg_last_interactionrtcamp.com/': {
+ parsedCookie: {
+ name: 'stg_last_interaction',
+ value: 'Tue%2C%2009%20Apr%202024%2008:04:56%20GMT',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: 'strict',
+ expires: '2025-04-09T08:04:56.000Z',
+ partitionKey: false,
+ size: 61,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'strict',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_last_interaction',
+ domain: '',
+ description:
+ "Determines whether the last visitor's session is still in progress or a new session has started.",
+ retention: '365 days',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838662,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838675,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838684,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838691,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838700,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838837,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838845,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839622,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893805,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896288,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ '_ga_7HKDVLRRV4rtcamp.com/': {
+ parsedCookie: {
+ name: '_ga_7HKDVLRRV4',
+ value: 'GS1.1.1712649839.11.0.1712649839.0.0.1798602937',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-14T08:03:59.200Z',
+ partitionKey: '',
+ size: 61,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: '_ga_*',
+ domain: 'google-analytics.com (3rd party) or ',
+ description: 'ID used to identify users',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '1',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838662,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838676,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838685,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838692,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838700,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838838,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838845,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839207,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839630,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893802,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893823,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896286,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_parsely_sessionrtcamp.com/': {
+ parsedCookie: {
+ name: '_parsely_session',
+ value:
+ '{%22sid%22:10%2C%22surl%22:%22https://rtcamp.com/%22%2C%22sref%22:%22%22%2C%22sts%22:1712649839162%2C%22slts%22:1712581949558}',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2024-04-09T08:35:00.000Z',
+ partitionKey: false,
+ size: 142,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'javascript',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839207,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839628,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893801,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893822,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896284,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'warmly_b4dafe8509a5fd61b4850acb8a60c06bopps-api.getwarmly.com/api/sessions/trpc':
+ {
+ isBlocked: true,
+ parsedCookie: {
+ domain: 'opps-api.getwarmly.com',
+ expires: '2025-04-05T09:33:25.133Z',
+ httpOnly: true,
+ name: 'warmly_b4dafe8509a5fd61b4850acb8a60c06b',
+ path: '/api/sessions/trpc',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'None',
+ secure: true,
+ session: false,
+ size: 172,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ '%7B%22sessionId%22%3A%22c75eb9a9-9ae9-43b8-b3da-5ceabbf59d44%22%2C%22sessionUserId%22%3A%2210dd5156-c0b4-4b75-966d-bc1b66ab6263%22%7D',
+ samesite: 'none',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.124',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839387,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['NotOnPath', 'DomainMismatch'],
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ },
+ 'FPLCrtcamp.com/': {
+ isBlocked: false,
+ blockedReasons: [],
+ parsedCookie: {
+ expires: '2024-04-10T04:03:59.874Z',
+ httponly: false,
+ secure: true,
+ path: '/',
+ domain: '.rtcamp.com',
+ samesite: '',
+ name: 'FPLC',
+ value:
+ '9cN4NZPh9L1TDUG1xtrXt9H%2BYwJihteKBHMDuZ9aDug1UQT8Y8XWjMkbh%2FCK9FcSi8XznsE9FnjtgaHtZpGd%2Ft7w5h%2Bfn%2Fc4%2BzAjYjPf%2FI9bYJT25qhdqJzArUMN9A%3D%3D',
+ partitionKey: '',
+ size: 150,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893804,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896287,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839876,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839882,
+ },
+ ],
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: 'FPLC',
+ domain: '',
+ description:
+ 'This FPLC cookie is the cross-domain linker cookie hashed from the FPID cookie. It’s not HttpOnly, which means it can be read with JavaScript. It has a relatively short lifetime, just 20 hours.',
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ isFirstParty: true,
+ headerType: 'request',
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ warningReasons: [],
+ },
+ 'FPGSIDrtcamp.com/': {
+ isBlocked: false,
+ blockedReasons: [],
+ parsedCookie: {
+ expires: '2024-04-09T08:33:59.874Z',
+ httponly: false,
+ secure: true,
+ path: '/',
+ domain: '.rtcamp.com',
+ samesite: 'strict',
+ name: 'FPGSID',
+ value: '1.1712649839.1712649839.G-7HKDVLRRV4.j1V_g8v-o4K7I5OKVAh_sQ',
+ partitionKey: '',
+ size: 65,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893805,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896288,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839877,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839883,
+ },
+ ],
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ isFirstParty: true,
+ headerType: 'request',
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ warningReasons: [],
+ },
+ 'NIDgoogle.com/': {
+ parsedCookie: {
+ name: 'NID',
+ value:
+ '513=fEZHdYbXcRMAOF3ZPEA3vRl9Dm7-B9JLfpLpTrtY3gDHBfo77B_V95BsxRPFvj7YXREgcHTvevfSVQwA7uWRBks6qoX0kKjqJ4I2zPwGXO436kL3thFCJu9nDXhnmGj6_Arpl_OQ8r50YccBg8N7qSxa2Dt_bhE7DnuyrRK91bv69GFnGAnpGEzA7pvdyPxB_WX9SQpPQ4U',
+ domain: '.google.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-10-07T21:20:50.696Z',
+ partitionKey: '',
+ size: 210,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google',
+ category: 'Marketing',
+ name: 'NID',
+ domain: 'google.com',
+ description:
+ 'This cookies is used to collect website statistics and track conversion rates and Google ad personalisation',
+ retention: '1 year',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://analytics.google.com/g/s/collect?dma=0>m=45j91e4441h2v882644066z871645728z99177835882za200&_gsid=7HKDVLRRV4j1V_g8v-o4K7I5OKVAh_sQ',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13109',
+ url: 'https://analytics.google.com/g/s/collect?dma=0>m=45j91e4441h2v882644066z871645728z99177835882za200&_gsid=7HKDVLRRV4j1V_g8v-o4K7I5OKVAh_sQ',
+ blocked: false,
+ timeStamp: 1712649839884,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840347,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13137',
+ url: 'https://www.google.com/pagead/1p-user-list/11351157933/?random=1712649842806&cv=11&fst=1712649600000&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&fmt=3&is_vtc=1&cid=CAQSKQB7FLtqntrNHDTQ_a-Sh9toqS56hqCzynlmLgQqmXr8fV3VRVs4WeVb&random=4222396660&rmt_tld=0&ipr=y',
+ blocked: false,
+ timeStamp: 1712649843058,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843116,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649893828,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13151',
+ url: 'https://accounts.google.com/gsi/client?ver=1670238691',
+ blocked: false,
+ timeStamp: 1712649893829,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13152',
+ url: 'https://accounts.google.com/gsi/style',
+ blocked: false,
+ timeStamp: 1712649893990,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649893992,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649893994,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13153',
+ url: 'https://accounts.google.com/gsi/status?client_id=549796576131-8aoqmiheqf84a8bh3dl10ec2kp2v6e7p.apps.googleusercontent.com&as=STPqYB%2FVV%2F9qmKJZpeo94A',
+ blocked: false,
+ timeStamp: 1712649894001,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894017,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13158',
+ url: 'https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ blocked: false,
+ timeStamp: 1712649894018,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13163',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649894142,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894146,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13169',
+ url: 'https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ blocked: false,
+ timeStamp: 1712649894150,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13170',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649894175,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894342,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894347,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13180',
+ url: 'https://www.google.com/js/bg/MAj5J5iEgh_vMgeickC5b2xvhmiD7VG83v9sx_9XVJI.js',
+ blocked: false,
+ timeStamp: 1712649894368,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13184',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894388,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13185',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894409,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894553,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13188',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894556,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13189',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894642,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13190',
+ url: 'https://www.google.com/js/bg/MAj5J5iEgh_vMgeickC5b2xvhmiD7VG83v9sx_9XVJI.js',
+ blocked: false,
+ timeStamp: 1712649894762,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13298',
+ url: 'https://accounts.google.com/gsi/style',
+ blocked: false,
+ timeStamp: 1712649896292,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13307',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649896294,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13311',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649896305,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13312',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649896313,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [108, 112, 109, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'JSESSIONIDads.kwanzoo.com/': {
+ blockedReasons: [
+ 'SameSiteUnspecifiedTreatedAsLax',
+ 'ExcludeSameSiteUnspecifiedTreatedAsLax',
+ ],
+ warningReasons: ['WarnSameSiteUnspecifiedCrossSiteContext'],
+ isBlocked: true,
+ parsedCookie: {
+ name: 'JSESSIONID',
+ value: '809D976D9AF74A799AA63ECAEFEADD53',
+ domain: 'ads.kwanzoo.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: '',
+ expires: 0,
+ partitionKey: '',
+ size: 42,
+ priority: 'Medium',
+ },
+ analytics: {
+ platform: 'J2EE',
+ category: 'Functional',
+ name: 'JSESSIONID*',
+ domain: '',
+ description:
+ 'JSESSIONID is a cookie generated by Servlet containers and used for session management in J2EE web applications for HTTP protocol. If a Web server is using a cookie for session management, it creates and sends JSESSIONID cookie to the client and then the client sends it back to the server in subsequent HTTP requests. JSESSIONID is a platform session cookie and is used by sites with JavaServer Pages (JSP). The cookie is used to maintain an anonymous user session by the server.',
+ retention: 'session',
+ dataController: 'J2EE',
+ gdprUrl: '',
+ wildcard: '1',
+ },
+ url: 'https://ads.kwanzoo.com/embed-code/12716',
+ networkEvents: {
+ requestEvents: [],
+ responseEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13101',
+ url: 'https://ads.kwanzoo.com/embed-code/12716',
+ blocked: true,
+ timeStamp: 1712649839949,
+ },
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: 'F4EF4E6A51A1059466A162665500CB39',
+ url: 'https://ads.kwanzoo.com/widget/inactive/12716',
+ blocked: true,
+ timeStamp: 1712649841164,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13111',
+ url: 'https://ads.kwanzoo.com/widget/inactive/12716',
+ blocked: true,
+ timeStamp: 1712649841167,
+ },
+ ],
+ },
+ headerType: 'response',
+ isFirstParty: false,
+ frameIdList: [106, 0],
+ blockingStatus: {
+ inboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ 'ar_debugdoubleclick.net/': {
+ parsedCookie: {
+ name: 'ar_debug',
+ value: '1',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-05-05T06:17:14.801Z',
+ partitionKey: '',
+ size: 9,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'ar_debug',
+ domain: 'doubleclick.net',
+ description: 'Store and track conversions',
+ retention: 'Persistent',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13112',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712649839982,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.134',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840188,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13135',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712649842806&cv=11&fst=1712649842806&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712649842825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13136',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649842828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.150',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649842975,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '704DD5D4D792F030A8AB9ABC9C058A42',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843026,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13310',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649896295,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [107, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'IDEdoubleclick.net/': {
+ parsedCookie: {
+ name: 'IDE',
+ value:
+ 'AHWqTUntbo9r3WXMBqKntf9Kmmoiu8TGRlI6Dk9N7YsxBDVIN3PiG8gseG6NChrjT6k',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2025-05-14T07:54:32.220Z',
+ partitionKey: '',
+ size: 70,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'IDE',
+ domain: 'doubleclick.net (3rd party)',
+ description:
+ 'This cookie is used for targeting, analyzing and optimisation of ad campaigns in DoubleClick/Google Marketing Suite',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13112',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712649839982,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.134',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840188,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13135',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712649842806&cv=11&fst=1712649842806&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712649842825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13136',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649842828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.150',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649842976,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '704DD5D4D792F030A8AB9ABC9C058A42',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843026,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13310',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649896295,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [107, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'DSIDdoubleclick.net/': {
+ parsedCookie: {
+ name: 'DSID',
+ value: 'NO_DATA',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-04-09T08:54:33.500Z',
+ partitionKey: '',
+ size: 11,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'DSID',
+ domain: 'doubleclick.net (3rd party)',
+ description:
+ 'This cookie is used for targeting, analyzing and optimisation of ad campaigns in DoubleClick/Google Marketing Suite',
+ retention: '2 weeks',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13112',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712649839983,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.134',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840189,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13135',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712649842806&cv=11&fst=1712649842806&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712649842825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13136',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649842828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.150',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649842976,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '704DD5D4D792F030A8AB9ABC9C058A42',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843027,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13310',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649896295,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [107, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'tuida.usbrowserspeed.com/': {
+ parsedCookie: {
+ name: 'tuid',
+ value: '1eadd2b3-4c04-4400-906c-71d58120510a',
+ domain: 'a.usbrowserspeed.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2025-04-09T08:04:01.027Z',
+ partitionKey: '',
+ size: 40,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'response',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13113',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ blocked: false,
+ timeStamp: 1712649840120,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.135',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840753,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.135',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649841025,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13113',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ blocked: false,
+ timeStamp: 1712649841028,
+ },
+ ],
+ },
+ isFirstParty: false,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ '_GRECAPTCHAwww.google.com/recaptcha': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: 'www.google.com',
+ expires: '2024-10-06T08:04:54.725Z',
+ httpOnly: true,
+ name: '_GRECAPTCHA',
+ path: '/recaptcha',
+ priority: 'High',
+ sameParty: false,
+ sameSite: 'None',
+ secure: true,
+ session: false,
+ size: 100,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ '09ABIEJouEaHgdO1cFbr1X9F69FvSW1TA4hefeRjfQpwlSVwkRSmYwrxz006dFw2R8FK3ECNOvT9iXt6HBfJwreQQ',
+ samesite: 'none',
+ partitionKey: '',
+ httponly: true,
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649840346,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649843115,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893827,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893990,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893993,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894016,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13158',
+ url: 'https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ blocked: false,
+ timeStamp: 1712649894017,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13163',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649894142,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894146,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13169',
+ url: 'https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ blocked: false,
+ timeStamp: 1712649894150,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13170',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649894174,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894342,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894345,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13184',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894388,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13185',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894409,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894552,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13188',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894555,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13189',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894641,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13307',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649896294,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13311',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649896305,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13312',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649896313,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13189',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894727,
+ },
+ ],
+ },
+ blockedReasons: ['NotOnPath', 'DomainMismatch'],
+ analytics: {
+ platform: 'Google reCAPTCHA',
+ category: 'Functional',
+ name: '_GRECAPTCHA',
+ domain: 'google.com',
+ description:
+ 'Google reCAPTCHA sets a necessary cookie (_GRECAPTCHA) when executed for the purpose of providing its risk analysis.',
+ retention: '179 days',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [108, 112, 109, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'SNIDgoogle.com/verify': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: '.google.com',
+ expires: '2024-10-05T06:36:29.696Z',
+ httpOnly: true,
+ name: 'SNID',
+ path: '/verify',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'Lax',
+ secure: true,
+ session: false,
+ size: 103,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ 'AOYECSr1AIksFOU_JTnc2ZZ-4TzCOICD8R03NsbLY3NmJpowc-xGVCb-BN4PM0erTr7W32PjsGaYrtD9kva2AlNWHsra2M4iwX8',
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649840346,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649843115,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893827,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893991,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893993,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894016,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894144,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894341,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894344,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894551,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['NotOnPath', 'SameSiteLax'],
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ warningReasons: [],
+ },
+ 'AECgoogle.com/': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: '.google.com',
+ expires: '2024-09-29T13:56:56.309Z',
+ httpOnly: true,
+ name: 'AEC',
+ path: '/',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'Lax',
+ secure: true,
+ session: false,
+ size: 61,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value: 'AQTF6HyG1VGHI6o8fu3nQ-FoJdbMr-JjFktcDDgVZYiHk1wSKkdoi-oXoQ',
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649840347,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649843116,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893991,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893994,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894016,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894145,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894341,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894345,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894552,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['SameSiteLax'],
+ analytics: {
+ platform: 'Google Ads',
+ category: 'Functional',
+ name: 'AEC',
+ domain: 'google.com',
+ description:
+ 'AEC cookies ensure that requests within a browsing session are made by the user, and not by other sites. These cookies prevent malicious sites from acting on behalf of a user without that user’s knowledge.',
+ retention: '6 months',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ warningReasons: [],
+ },
+ 'cookietestrtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: 'Session',
+ name: 'cookietest',
+ partitioned: false,
+ path: '/',
+ sameSite: 'lax',
+ secure: false,
+ value: '1',
+ partitionKey: false,
+ size: 11,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ 'stg_traffic_source_priorityrtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: '2024-04-09T08:34:56.000Z',
+ name: 'stg_traffic_source_priority',
+ partitioned: false,
+ path: '/',
+ sameSite: 'strict',
+ secure: false,
+ value: '1',
+ partitionKey: false,
+ size: 28,
+ httponly: false,
+ samesite: 'strict',
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893803,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893823,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896286,
+ },
+ ],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_traffic_source_priority',
+ domain: '',
+ description:
+ 'Stores the type of traffic source that explains how the visitor reached your website.',
+ retention: '30 minutes',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ '_pk_ses.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59rtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: '2024-04-09T08:34:56.000Z',
+ name: '_pk_ses.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59',
+ partitioned: false,
+ path: '/',
+ sameSite: 'lax',
+ secure: true,
+ value: '*',
+ partitionKey: '',
+ size: 50,
+ priority: 'Medium',
+ httponly: false,
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893804,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896287,
+ },
+ ],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: 'Matomo',
+ category: 'Analytics',
+ name: '_pk_ses*',
+ domain: '',
+ description:
+ 'Short lived cookies used to temporarily store data for the visit',
+ retention: '30 minutes',
+ dataController: 'Matomo',
+ gdprUrl: 'https://matomo.org/privacy-policy/',
+ wildcard: '1',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+};
+
+export const tabFrames = {
+ 'https://rtcamp.com': {
+ frameIds: [0],
+ frameType: 'outermost_frame',
+ isOnRWS: false,
+ },
+ 'https://ads.kwanzoo.com': {
+ frameIds: [106],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ 'https://td.doubleclick.net': {
+ frameIds: [107],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ 'https://www.google.com': {
+ frameIds: [108, 109, 112],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+};
+
+export const libraryMatches = {
+ gsiV2: {
+ signatureMatches: 0,
+ matches: [],
+ moduleMatch: 0,
+ },
+ gis: {
+ signatureMatches: 0,
+ matches: [],
+ },
+ 'fb-comments': {
+ domQuerymatches: [],
+ },
+ 'fb-likes': {
+ domQuerymatches: [],
+ },
+ 'disqus-comments': {
+ domQuerymatches: [],
+ },
+ 'jetpack-comments': {
+ domQuerymatches: [],
+ },
+ 'jetpack-likes': {
+ domQuerymatches: [],
+ },
+ reCaptcha: {
+ domQuerymatches: [
+ 'script[src]: https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ 'script[src]: https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ ],
+ },
+};
+
+export const data = {
+ cookieClassificationDataMapping: [
+ {
+ title: 'Total cookies',
+ count: 29,
+ data: [
+ {
+ label: 'Functional',
+ count: 3,
+ color: '#5CC971',
+ countClassName: 'text-functional',
+ },
+ {
+ label: 'Marketing',
+ count: 6,
+ color: '#F3AE4E',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Analytics',
+ count: 12,
+ color: '#4C79F4',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Uncategorized',
+ count: 8,
+ color: '#EC7159',
+ countClassName: 'text-uncategorised',
+ },
+ ],
+ },
+ {
+ title: '1st party cookies',
+ count: 19,
+ data: [
+ {
+ count: 0,
+ color: '#5CC971',
+ },
+ {
+ count: 2,
+ color: '#F3AE4E',
+ },
+ {
+ count: 12,
+ color: '#4C79F4',
+ },
+ {
+ count: 5,
+ color: '#EC7159',
+ },
+ ],
+ },
+ {
+ title: '3rd party cookies',
+ count: 10,
+ data: [
+ {
+ count: 3,
+ color: '#5CC971',
+ },
+ {
+ count: 4,
+ color: '#F3AE4E',
+ },
+ {
+ count: 0,
+ color: '#4C79F4',
+ },
+ {
+ count: 3,
+ color: '#EC7159',
+ },
+ ],
+ },
+ ],
+ tabCookies: {
+ '_gcl_aurtcamp.com/': {
+ parsedCookie: {
+ name: '_gcl_au',
+ value: '1.1.1643004070.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2024-07-02T05:40:12.000Z',
+ partitionKey: '',
+ size: 32,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: 'Google',
+ category: 'Marketing',
+ name: '_gcl_au',
+ domain: '',
+ description:
+ 'Used by Google AdSense for experimenting with advertisement efficiency across websites using their services.',
+ retention: '3 months',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838658,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838663,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838679,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838685,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838694,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838713,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838838,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839204,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839623,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893820,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_user_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_user_id',
+ value: 'null',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 15,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_user_id',
+ domain: '.trustpilot.com',
+ description:
+ ' This cookie helps track visitor usage, events, target marketing, and can also measure application performance and stability.',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838679,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838685,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838694,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838715,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838839,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893820,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_group_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_group_id',
+ value: 'null',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 16,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_group_id',
+ domain: '.trustpilot.com',
+ description: 'Track visitor usage and events within the website',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838679,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838686,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838695,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838810,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893820,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_anonymous_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_anonymous_id',
+ value: '%220eae481f-71ad-4118-9309-1f60ae8f9f6d%22',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 58,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_anonymous_id',
+ domain: '.trustpilot.com',
+ description:
+ 'Used for Analytics and help count how many people visit a certain site by tracking if you have visited before',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838680,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838686,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838695,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893798,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896282,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_gartcamp.com/': {
+ parsedCookie: {
+ name: '_ga',
+ value: 'GA1.1.1593307359.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-14T08:03:59.200Z',
+ partitionKey: '',
+ size: 30,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: '_ga',
+ domain: 'google-analytics.com (3rd party) or',
+ description: 'ID used to identify users',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838659,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838680,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838687,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838696,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839205,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839625,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893799,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896283,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'FPIDrtcamp.com/': {
+ parsedCookie: {
+ name: 'FPID',
+ value:
+ 'FPID2.2.BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: '',
+ expires: '2025-05-14T08:03:59.874Z',
+ partitionKey: '',
+ size: 71,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: 'FPID',
+ domain: '',
+ description:
+ "Registers statistical data on users' behaviour on the website. Used for internal analytics by the website operator.",
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838660,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838664,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838671,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838680,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838687,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838696,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839206,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839626,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893799,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896283,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839875,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839882,
+ },
+ ],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'FPAUrtcamp.com/': {
+ parsedCookie: {
+ name: 'FPAU',
+ value: '1.1.1643004070.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: '',
+ expires: '2024-07-02T05:40:11.874Z',
+ partitionKey: '',
+ size: 29,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Marketing',
+ name: 'FPAU',
+ domain: '',
+ description:
+ 'Assigns a specific ID to the visitor. This allows the website to determine the number of specific user-visits for analysis and statistics.',
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838660,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838665,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838668,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838672,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838681,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838688,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838696,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838840,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839206,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839626,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893799,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893821,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896283,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839876,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839882,
+ },
+ ],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'track_uidrtcamp.com/': {
+ parsedCookie: {
+ name: 'track_uid',
+ value: 'df985b92-a92b-7c79-35c7-3030565fd182',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-09T08:04:01.000Z',
+ partitionKey: '',
+ size: 45,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838661,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838665,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838669,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838673,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838682,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838688,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838697,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838841,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839206,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839626,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893800,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893822,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896284,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'stg_returning_visitorrtcamp.com/': {
+ parsedCookie: {
+ name: 'stg_returning_visitor',
+ value: 'Wed%2C%2003%20Apr%202024%2008:00:23%20GMT',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: 'strict',
+ expires: '2025-04-03T08:00:23.000Z',
+ partitionKey: '',
+ size: 62,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'Strict',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_returning_visitor',
+ domain: '',
+ description:
+ 'Determines if the visitor has already been to your website — they are returning visitors.',
+ retention: '365 days',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838661,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838669,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838673,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838682,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838689,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838698,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838826,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838841,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839621,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893800,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893822,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896284,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ '_parsely_visitorrtcamp.com/': {
+ parsedCookie: {
+ name: '_parsely_visitor',
+ value:
+ '{%22id%22:%22pid=55cc8d59-04cf-4bcd-aaca-5e6bb9ca7cc4%22%2C%22session_count%22:10%2C%22last_session_ts%22:1712649839162}',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-09T18:05:00.000Z',
+ partitionKey: false,
+ size: 136,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838661,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838669,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838674,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838683,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838690,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838699,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838826,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838844,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839207,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839629,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893802,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893823,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896285,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_pk_id.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59rtcamp.com/': {
+ parsedCookie: {
+ name: '_pk_id.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59',
+ value: 'e232543d43714eb7.1712122813.9.1712649896.1712649840.',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: 'lax',
+ expires: '2025-05-07T08:04:56.000Z',
+ partitionKey: '',
+ size: 100,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'lax',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ },
+ analytics: {
+ platform: 'Matomo',
+ category: 'Analytics',
+ name: '_pk_id*',
+ domain: '',
+ description:
+ 'Used to store a few details about the user such as the unique visitor ID',
+ retention: '13 months',
+ dataController: 'Matomo',
+ gdprUrl: 'https://matomo.org/privacy-policy/',
+ wildcard: '1',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838662,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838675,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838684,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838691,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838699,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838837,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838844,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839621,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893805,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896290,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ 'stg_last_interactionrtcamp.com/': {
+ parsedCookie: {
+ name: 'stg_last_interaction',
+ value: 'Tue%2C%2009%20Apr%202024%2008:04:56%20GMT',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: 'strict',
+ expires: '2025-04-09T08:04:56.000Z',
+ partitionKey: false,
+ size: 61,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'strict',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_last_interaction',
+ domain: '',
+ description:
+ "Determines whether the last visitor's session is still in progress or a new session has started.",
+ retention: '365 days',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838662,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838666,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838675,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838684,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838691,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838700,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838837,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838845,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839622,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893805,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896288,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ '_ga_7HKDVLRRV4rtcamp.com/': {
+ parsedCookie: {
+ name: '_ga_7HKDVLRRV4',
+ value: 'GS1.1.1712649839.11.0.1712649839.0.0.1798602937',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-14T08:03:59.200Z',
+ partitionKey: '',
+ size: 61,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: '_ga_*',
+ domain: 'google-analytics.com (3rd party) or ',
+ description: 'ID used to identify users',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '1',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13079',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712649838662,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13080',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712649838667,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13081',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712649838670,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13082',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712649838676,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13089',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712649838685,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13090',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712649838692,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13092',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712649838700,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13093',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712649838838,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13094',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712649838845,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839207,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839630,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893802,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893823,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896286,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_parsely_sessionrtcamp.com/': {
+ parsedCookie: {
+ name: '_parsely_session',
+ value:
+ '{%22sid%22:10%2C%22surl%22:%22https://rtcamp.com/%22%2C%22sref%22:%22%22%2C%22sts%22:1712649839162%2C%22slts%22:1712581949558}',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2024-04-09T08:35:00.000Z',
+ partitionKey: false,
+ size: 142,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'javascript',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839207,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839628,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893801,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893822,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896284,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'warmly_b4dafe8509a5fd61b4850acb8a60c06bopps-api.getwarmly.com/api/sessions/trpc':
+ {
+ isBlocked: true,
+ parsedCookie: {
+ domain: 'opps-api.getwarmly.com',
+ expires: '2025-04-05T09:33:25.133Z',
+ httpOnly: true,
+ name: 'warmly_b4dafe8509a5fd61b4850acb8a60c06b',
+ path: '/api/sessions/trpc',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'None',
+ secure: true,
+ session: false,
+ size: 172,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ '%7B%22sessionId%22%3A%22c75eb9a9-9ae9-43b8-b3da-5ceabbf59d44%22%2C%22sessionUserId%22%3A%2210dd5156-c0b4-4b75-966d-bc1b66ab6263%22%7D',
+ samesite: 'none',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.124',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649839387,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['NotOnPath', 'DomainMismatch'],
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ },
+ 'FPLCrtcamp.com/': {
+ isBlocked: false,
+ blockedReasons: [],
+ parsedCookie: {
+ expires: '2024-04-10T04:03:59.874Z',
+ httponly: false,
+ secure: true,
+ path: '/',
+ domain: '.rtcamp.com',
+ samesite: '',
+ name: 'FPLC',
+ value:
+ '9cN4NZPh9L1TDUG1xtrXt9H%2BYwJihteKBHMDuZ9aDug1UQT8Y8XWjMkbh%2FCK9FcSi8XznsE9FnjtgaHtZpGd%2Ft7w5h%2Bfn%2Fc4%2BzAjYjPf%2FI9bYJT25qhdqJzArUMN9A%3D%3D',
+ partitionKey: '',
+ size: 150,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893804,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896287,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839876,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839882,
+ },
+ ],
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: 'FPLC',
+ domain: '',
+ description:
+ 'This FPLC cookie is the cross-domain linker cookie hashed from the FPID cookie. It’s not HttpOnly, which means it can be read with JavaScript. It has a relatively short lifetime, just 20 hours.',
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ isFirstParty: true,
+ headerType: 'request',
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ warningReasons: [],
+ },
+ 'FPGSIDrtcamp.com/': {
+ isBlocked: false,
+ blockedReasons: [],
+ parsedCookie: {
+ expires: '2024-04-09T08:33:59.874Z',
+ httponly: false,
+ secure: true,
+ path: '/',
+ domain: '.rtcamp.com',
+ samesite: 'strict',
+ name: 'FPGSID',
+ value: '1.1712649839.1712649839.G-7HKDVLRRV4.j1V_g8v-o4K7I5OKVAh_sQ',
+ partitionKey: '',
+ size: 65,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893805,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896288,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.126',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649839877,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13104',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712649838568&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1798602937&ul=en-us&sr=1440x900&_fplc=0&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712649838568&sst.ude=0&_s=1&sid=1712649839&sct=11&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1037&richsstsse',
+ blocked: false,
+ timeStamp: 1712649839883,
+ },
+ ],
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ isFirstParty: true,
+ headerType: 'request',
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ warningReasons: [],
+ },
+ 'NIDgoogle.com/': {
+ parsedCookie: {
+ name: 'NID',
+ value:
+ '513=fEZHdYbXcRMAOF3ZPEA3vRl9Dm7-B9JLfpLpTrtY3gDHBfo77B_V95BsxRPFvj7YXREgcHTvevfSVQwA7uWRBks6qoX0kKjqJ4I2zPwGXO436kL3thFCJu9nDXhnmGj6_Arpl_OQ8r50YccBg8N7qSxa2Dt_bhE7DnuyrRK91bv69GFnGAnpGEzA7pvdyPxB_WX9SQpPQ4U',
+ domain: '.google.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-10-07T21:20:50.696Z',
+ partitionKey: '',
+ size: 210,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google',
+ category: 'Marketing',
+ name: 'NID',
+ domain: 'google.com',
+ description:
+ 'This cookies is used to collect website statistics and track conversion rates and Google ad personalisation',
+ retention: '1 year',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://analytics.google.com/g/s/collect?dma=0>m=45j91e4441h2v882644066z871645728z99177835882za200&_gsid=7HKDVLRRV4j1V_g8v-o4K7I5OKVAh_sQ',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13109',
+ url: 'https://analytics.google.com/g/s/collect?dma=0>m=45j91e4441h2v882644066z871645728z99177835882za200&_gsid=7HKDVLRRV4j1V_g8v-o4K7I5OKVAh_sQ',
+ blocked: false,
+ timeStamp: 1712649839884,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840347,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13137',
+ url: 'https://www.google.com/pagead/1p-user-list/11351157933/?random=1712649842806&cv=11&fst=1712649600000&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&fmt=3&is_vtc=1&cid=CAQSKQB7FLtqntrNHDTQ_a-Sh9toqS56hqCzynlmLgQqmXr8fV3VRVs4WeVb&random=4222396660&rmt_tld=0&ipr=y',
+ blocked: false,
+ timeStamp: 1712649843058,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843116,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649893828,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13151',
+ url: 'https://accounts.google.com/gsi/client?ver=1670238691',
+ blocked: false,
+ timeStamp: 1712649893829,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13152',
+ url: 'https://accounts.google.com/gsi/style',
+ blocked: false,
+ timeStamp: 1712649893990,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649893992,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649893994,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13153',
+ url: 'https://accounts.google.com/gsi/status?client_id=549796576131-8aoqmiheqf84a8bh3dl10ec2kp2v6e7p.apps.googleusercontent.com&as=STPqYB%2FVV%2F9qmKJZpeo94A',
+ blocked: false,
+ timeStamp: 1712649894001,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894017,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13158',
+ url: 'https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ blocked: false,
+ timeStamp: 1712649894018,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13163',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649894142,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894146,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13169',
+ url: 'https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ blocked: false,
+ timeStamp: 1712649894150,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13170',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649894175,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894342,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894347,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13180',
+ url: 'https://www.google.com/js/bg/MAj5J5iEgh_vMgeickC5b2xvhmiD7VG83v9sx_9XVJI.js',
+ blocked: false,
+ timeStamp: 1712649894368,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13184',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894388,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13185',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894409,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894553,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13188',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894556,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13189',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894642,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13190',
+ url: 'https://www.google.com/js/bg/MAj5J5iEgh_vMgeickC5b2xvhmiD7VG83v9sx_9XVJI.js',
+ blocked: false,
+ timeStamp: 1712649894762,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13298',
+ url: 'https://accounts.google.com/gsi/style',
+ blocked: false,
+ timeStamp: 1712649896292,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13307',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649896294,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13311',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649896305,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13312',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649896313,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [108, 112, 109, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'JSESSIONIDads.kwanzoo.com/': {
+ blockedReasons: [
+ 'SameSiteUnspecifiedTreatedAsLax',
+ 'ExcludeSameSiteUnspecifiedTreatedAsLax',
+ ],
+ warningReasons: ['WarnSameSiteUnspecifiedCrossSiteContext'],
+ isBlocked: true,
+ parsedCookie: {
+ name: 'JSESSIONID',
+ value: '809D976D9AF74A799AA63ECAEFEADD53',
+ domain: 'ads.kwanzoo.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: '',
+ expires: 0,
+ partitionKey: '',
+ size: 42,
+ priority: 'Medium',
+ },
+ analytics: {
+ platform: 'J2EE',
+ category: 'Functional',
+ name: 'JSESSIONID*',
+ domain: '',
+ description:
+ 'JSESSIONID is a cookie generated by Servlet containers and used for session management in J2EE web applications for HTTP protocol. If a Web server is using a cookie for session management, it creates and sends JSESSIONID cookie to the client and then the client sends it back to the server in subsequent HTTP requests. JSESSIONID is a platform session cookie and is used by sites with JavaServer Pages (JSP). The cookie is used to maintain an anonymous user session by the server.',
+ retention: 'session',
+ dataController: 'J2EE',
+ gdprUrl: '',
+ wildcard: '1',
+ },
+ url: 'https://ads.kwanzoo.com/embed-code/12716',
+ networkEvents: {
+ requestEvents: [],
+ responseEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13101',
+ url: 'https://ads.kwanzoo.com/embed-code/12716',
+ blocked: true,
+ timeStamp: 1712649839949,
+ },
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: 'F4EF4E6A51A1059466A162665500CB39',
+ url: 'https://ads.kwanzoo.com/widget/inactive/12716',
+ blocked: true,
+ timeStamp: 1712649841164,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13111',
+ url: 'https://ads.kwanzoo.com/widget/inactive/12716',
+ blocked: true,
+ timeStamp: 1712649841167,
+ },
+ ],
+ },
+ headerType: 'response',
+ isFirstParty: false,
+ frameIdList: [106, 0],
+ blockingStatus: {
+ inboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ 'ar_debugdoubleclick.net/': {
+ parsedCookie: {
+ name: 'ar_debug',
+ value: '1',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-05-05T06:17:14.801Z',
+ partitionKey: '',
+ size: 9,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'ar_debug',
+ domain: 'doubleclick.net',
+ description: 'Store and track conversions',
+ retention: 'Persistent',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13112',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712649839982,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.134',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840188,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13135',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712649842806&cv=11&fst=1712649842806&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712649842825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13136',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649842828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.150',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649842975,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '704DD5D4D792F030A8AB9ABC9C058A42',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843026,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13310',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649896295,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [107, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'IDEdoubleclick.net/': {
+ parsedCookie: {
+ name: 'IDE',
+ value:
+ 'AHWqTUntbo9r3WXMBqKntf9Kmmoiu8TGRlI6Dk9N7YsxBDVIN3PiG8gseG6NChrjT6k',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2025-05-14T07:54:32.220Z',
+ partitionKey: '',
+ size: 70,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'IDE',
+ domain: 'doubleclick.net (3rd party)',
+ description:
+ 'This cookie is used for targeting, analyzing and optimisation of ad campaigns in DoubleClick/Google Marketing Suite',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13112',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712649839982,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.134',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840188,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13135',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712649842806&cv=11&fst=1712649842806&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712649842825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13136',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649842828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.150',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649842976,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '704DD5D4D792F030A8AB9ABC9C058A42',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843026,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13310',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649896295,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [107, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'DSIDdoubleclick.net/': {
+ parsedCookie: {
+ name: 'DSID',
+ value: 'NO_DATA',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-04-09T08:54:33.500Z',
+ partitionKey: '',
+ size: 11,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'DSID',
+ domain: 'doubleclick.net (3rd party)',
+ description:
+ 'This cookie is used for targeting, analyzing and optimisation of ad campaigns in DoubleClick/Google Marketing Suite',
+ retention: '2 weeks',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13112',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4441h2v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712649839983,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.134',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840189,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13135',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712649842806&cv=11&fst=1712649842806&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712649842825,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13136',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649842828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.150',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649842976,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '704DD5D4D792F030A8AB9ABC9C058A42',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649843027,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13310',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712649842806&cv=11&fst=1712649842806&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712649896295,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [107, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'tuida.usbrowserspeed.com/': {
+ parsedCookie: {
+ name: 'tuid',
+ value: '1eadd2b3-4c04-4400-906c-71d58120510a',
+ domain: 'a.usbrowserspeed.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2025-04-09T08:04:01.027Z',
+ partitionKey: '',
+ size: 40,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'response',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13113',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ blocked: false,
+ timeStamp: 1712649840120,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.135',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649840753,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '82785.135',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649841025,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13113',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ blocked: false,
+ timeStamp: 1712649841028,
+ },
+ ],
+ },
+ isFirstParty: false,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ '_GRECAPTCHAwww.google.com/recaptcha': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: 'www.google.com',
+ expires: '2024-10-06T08:04:54.725Z',
+ httpOnly: true,
+ name: '_GRECAPTCHA',
+ path: '/recaptcha',
+ priority: 'High',
+ sameParty: false,
+ sameSite: 'None',
+ secure: true,
+ session: false,
+ size: 100,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ '09ABIEJouEaHgdO1cFbr1X9F69FvSW1TA4hefeRjfQpwlSVwkRSmYwrxz006dFw2R8FK3ECNOvT9iXt6HBfJwreQQ',
+ samesite: 'none',
+ partitionKey: '',
+ httponly: true,
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649840346,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649843115,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893827,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893990,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893993,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894016,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13158',
+ url: 'https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ blocked: false,
+ timeStamp: 1712649894017,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13163',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649894142,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894146,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13169',
+ url: 'https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ blocked: false,
+ timeStamp: 1712649894150,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13170',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649894174,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894342,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894345,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13184',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894388,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13185',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712649894409,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: false,
+ timeStamp: 1712649894552,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13188',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894555,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13189',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894641,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13307',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=64wrh1hrhyl0',
+ blocked: false,
+ timeStamp: 1712649896294,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13311',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649896305,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13312',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=1jzcq6kj791e',
+ blocked: false,
+ timeStamp: 1712649896313,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '13189',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712649894727,
+ },
+ ],
+ },
+ blockedReasons: ['NotOnPath', 'DomainMismatch'],
+ analytics: {
+ platform: 'Google reCAPTCHA',
+ category: 'Functional',
+ name: '_GRECAPTCHA',
+ domain: 'google.com',
+ description:
+ 'Google reCAPTCHA sets a necessary cookie (_GRECAPTCHA) when executed for the purpose of providing its risk analysis.',
+ retention: '179 days',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [108, 112, 109, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'SNIDgoogle.com/verify': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: '.google.com',
+ expires: '2024-10-05T06:36:29.696Z',
+ httpOnly: true,
+ name: 'SNID',
+ path: '/verify',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'Lax',
+ secure: true,
+ session: false,
+ size: 103,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ 'AOYECSr1AIksFOU_JTnc2ZZ-4TzCOICD8R03NsbLY3NmJpowc-xGVCb-BN4PM0erTr7W32PjsGaYrtD9kva2AlNWHsra2M4iwX8',
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649840346,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649843115,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893827,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893991,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893993,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894016,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894144,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894341,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894344,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894551,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['NotOnPath', 'SameSiteLax'],
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ warningReasons: [],
+ },
+ 'AECgoogle.com/': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: '.google.com',
+ expires: '2024-09-29T13:56:56.309Z',
+ httpOnly: true,
+ name: 'AEC',
+ path: '/',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'Lax',
+ secure: true,
+ session: false,
+ size: 61,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value: 'AQTF6HyG1VGHI6o8fu3nQ-FoJdbMr-JjFktcDDgVZYiHk1wSKkdoi-oXoQ',
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.132',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649840347,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.151',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649843116,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.181',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893828,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893991,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.183',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649893994,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.192',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894016,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '82785.208',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894145,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '171EF73AC49739330627AF0ECE168B24',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894341,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '71BEDF59BFFA5B219605F36AF92F46A2',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894345,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: 'BC0D70D08304A7434BAB6334EFAC0866',
+ url: '',
+ blocked: true,
+ timeStamp: 1712649894552,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['SameSiteLax'],
+ analytics: {
+ platform: 'Google Ads',
+ category: 'Functional',
+ name: 'AEC',
+ domain: 'google.com',
+ description:
+ 'AEC cookies ensure that requests within a browsing session are made by the user, and not by other sites. These cookies prevent malicious sites from acting on behalf of a user without that user’s knowledge.',
+ retention: '6 months',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ warningReasons: [],
+ },
+ 'cookietestrtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: 'Session',
+ name: 'cookietest',
+ partitioned: false,
+ path: '/',
+ sameSite: 'lax',
+ secure: false,
+ value: '1',
+ partitionKey: false,
+ size: 11,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ 'stg_traffic_source_priorityrtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: '2024-04-09T08:34:56.000Z',
+ name: 'stg_traffic_source_priority',
+ partitioned: false,
+ path: '/',
+ sameSite: 'strict',
+ secure: false,
+ value: '1',
+ partitionKey: false,
+ size: 28,
+ httponly: false,
+ samesite: 'strict',
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893803,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893823,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896286,
+ },
+ ],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_traffic_source_priority',
+ domain: '',
+ description:
+ 'Stores the type of traffic source that explains how the visitor reached your website.',
+ retention: '30 minutes',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ '_pk_ses.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59rtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: '2024-04-09T08:34:56.000Z',
+ name: '_pk_ses.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59',
+ partitioned: false,
+ path: '/',
+ sameSite: 'lax',
+ secure: true,
+ value: '*',
+ partitionKey: '',
+ size: 50,
+ priority: 'Medium',
+ httponly: false,
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13144',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712649893804,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13149',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712649893824,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '13291',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712649896287,
+ },
+ ],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: 'Matomo',
+ category: 'Analytics',
+ name: '_pk_ses*',
+ domain: '',
+ description:
+ 'Short lived cookies used to temporarily store data for the visit',
+ retention: '30 minutes',
+ dataController: 'Matomo',
+ gdprUrl: 'https://matomo.org/privacy-policy/',
+ wildcard: '1',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ },
+ cookiesStatsComponents: {
+ legend: [
+ {
+ label: 'Functional',
+ count: 3,
+ color: '#5CC971',
+ countClassName: 'text-functional',
+ },
+ {
+ label: 'Marketing',
+ count: 6,
+ color: '#F3AE4E',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Analytics',
+ count: 12,
+ color: '#4C79F4',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Uncategorized',
+ count: 8,
+ color: '#EC7159',
+ countClassName: 'text-uncategorised',
+ },
+ ],
+ firstParty: [
+ {
+ count: 0,
+ color: '#5CC971',
+ },
+ {
+ count: 2,
+ color: '#F3AE4E',
+ },
+ {
+ count: 12,
+ color: '#4C79F4',
+ },
+ {
+ count: 5,
+ color: '#EC7159',
+ },
+ ],
+ thirdParty: [
+ {
+ count: 3,
+ color: '#5CC971',
+ },
+ {
+ count: 4,
+ color: '#F3AE4E',
+ },
+ {
+ count: 0,
+ color: '#4C79F4',
+ },
+ {
+ count: 3,
+ color: '#EC7159',
+ },
+ ],
+ blocked: [
+ {
+ count: 5,
+ color: '#7D8471',
+ },
+ {
+ count: 3,
+ color: '#79553D',
+ },
+ {
+ count: 1,
+ color: '#FF7514',
+ },
+ {
+ count: 1,
+ color: '#1C542D',
+ },
+ {
+ count: 2,
+ color: '#FFA420',
+ },
+ ],
+ blockedCookiesLegend: [
+ {
+ label: 'DomainMismatch',
+ count: 5,
+ color: '#7D8471',
+ countClassName: 'text-battle-dress',
+ },
+ {
+ label: 'NotOnPath',
+ count: 3,
+ color: '#79553D',
+ countClassName: 'text-brownstone',
+ },
+ {
+ label: 'SameSiteUnspecifiedTreatedAsLax',
+ count: 1,
+ color: '#FF7514',
+ countClassName: 'text-sparks-in-green',
+ },
+ {
+ label: 'ExcludeSameSiteUnspecifiedTreatedAsLax',
+ count: 1,
+ color: '#1C542D',
+ countClassName: 'text-jay-bird',
+ },
+ {
+ label: 'SameSiteLax',
+ count: 2,
+ color: '#FFA420',
+ countClassName: 'text-honey-wax',
+ },
+ ],
+ exempted: [],
+ exemptedCookiesLegend: [],
+ },
+ tabFrames: {
+ 'https://rtcamp.com': {
+ frameIds: [0],
+ frameType: 'outermost_frame',
+ isOnRWS: false,
+ },
+ 'https://ads.kwanzoo.com': {
+ frameIds: [106],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ 'https://td.doubleclick.net': {
+ frameIds: [107],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ 'https://www.google.com': {
+ frameIds: [108, 109, 112],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ },
+ showInfoIcon: true,
+ showHorizontalMatrix: false,
+ blockedCookieDataMapping: [
+ {
+ title: 'Blocked cookies',
+ count: 8,
+ data: [
+ {
+ count: 5,
+ color: '#7D8471',
+ },
+ {
+ count: 3,
+ color: '#79553D',
+ },
+ {
+ count: 1,
+ color: '#FF7514',
+ },
+ {
+ count: 1,
+ color: '#1C542D',
+ },
+ {
+ count: 2,
+ color: '#FFA420',
+ },
+ ],
+ },
+ ],
+ showBlockedInfoIcon: true,
+ frameStateCreator: {
+ dataMapping: [
+ {
+ title: 'Frames',
+ count: 4,
+ data: [
+ {
+ count: 4,
+ color: '#25ACAD',
+ },
+ {
+ count: 3,
+ color: '#F54021',
+ },
+ {
+ count: 3,
+ color: '#AF7AA3',
+ },
+ {
+ count: 4,
+ color: '#C5A06A',
+ },
+ {
+ count: 0,
+ color: '#A98307',
+ },
+ ],
+ },
+ ],
+ legend: [
+ {
+ label: 'Total frames',
+ count: 4,
+ color: '#25ACAD',
+ countClassName: 'text-greenland-green',
+ },
+ {
+ label: 'Frames with cookies',
+ count: 4,
+ color: '#C5A06A',
+ countClassName: 'text-good-life',
+ },
+ {
+ label: 'Frames with blocked cookies',
+ count: 3,
+ color: '#AF7AA3',
+ countClassName: 'text-victorian-violet',
+ },
+ {
+ label: 'Frames with unblocked cookies',
+ count: 3,
+ color: '#F54021',
+ countClassName: 'text-strawberry-spinach-red',
+ },
+ {
+ label: 'Fenced frames',
+ count: 0,
+ color: '#A98307',
+ countClassName: 'text-chestnut-gold',
+ },
+ ],
+ },
+ libraryMatches: {
+ gsiV2: {
+ signatureMatches: 0,
+ matches: [],
+ moduleMatch: 0,
+ },
+ gis: {
+ signatureMatches: 0,
+ matches: [],
+ },
+ 'fb-comments': {
+ domQuerymatches: [],
+ },
+ 'fb-likes': {
+ domQuerymatches: [],
+ },
+ 'disqus-comments': {
+ domQuerymatches: [],
+ },
+ 'jetpack-comments': {
+ domQuerymatches: [],
+ },
+ 'jetpack-likes': {
+ domQuerymatches: [],
+ },
+ reCaptcha: {
+ domQuerymatches: [
+ 'script[src]: https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ 'script[src]: https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ ],
+ },
+ },
+ exemptedCookiesDataMapping: [
+ {
+ count: 0,
+ data: [],
+ title: 'Exempted cookies',
+ },
+ ],
+};
diff --git a/packages/extension/src/utils/tests/generateReportObject.ts b/packages/extension/src/utils/tests/generateReportObject.ts
new file mode 100644
index 000000000..69042533e
--- /dev/null
+++ b/packages/extension/src/utils/tests/generateReportObject.ts
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import generateReportObject from '../generateReportObject';
+import { data, libraryMatches, tabCookies, tabFrames } from './data.mock';
+
+describe('generateReport', () => {
+ it('should generate report object', () => {
+ expect(
+ //@ts-ignore
+ generateReportObject(tabCookies, tabFrames, libraryMatches)
+ ).toEqual(data);
+ });
+});
diff --git a/packages/extension/src/utils/tests/getFramesForCurrentTab.ts b/packages/extension/src/utils/tests/getFramesForCurrentTab.ts
new file mode 100644
index 000000000..ea6e1e415
--- /dev/null
+++ b/packages/extension/src/utils/tests/getFramesForCurrentTab.ts
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Internal dependencies.
+ */
+import tabFrames from '../test-data/tabFrames';
+import getFramesForCurrentTab from '../getFramesForCurrentTab';
+// @ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import RelatedWebsitesSets from 'ps-analysis-tool/data/related_website_sets.json';
+
+describe('getFramesForCurrentTab : ', () => {
+ beforeAll(() => {
+ //@ts-ignore
+ globalThis.chrome = {
+ devtools: {
+ //@ts-ignore
+ inspectedWindow: {
+ tabId: 40245632,
+ },
+ },
+ //@ts-ignore
+ runtime: {
+ getURL: () => 'data/related_website_sets.json',
+ },
+ //@ts-ignore
+ webNavigation: {
+ //@ts-ignore
+ getAllFrames: () => {
+ return Promise.resolve(tabFrames);
+ },
+ },
+ };
+
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...RelatedWebsitesSets,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('Should not return tab when tabId is negative', async () => {
+ expect(await getFramesForCurrentTab()).toStrictEqual({
+ 'https://edition.cnn.com': {
+ frameIds: [0, 3],
+ isOnRWS: false,
+ frameType: 'outermost_frame',
+ },
+ 'https://crxd.net': {
+ frameIds: [2],
+ isOnRWS: false,
+ frameType: 'sub_frame',
+ },
+ });
+ });
+});
diff --git a/packages/extension/src/utils/tests/parseHeaders.ts b/packages/extension/src/utils/tests/parseHeaders.ts
new file mode 100644
index 000000000..e1fdc5aad
--- /dev/null
+++ b/packages/extension/src/utils/tests/parseHeaders.ts
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import SinonChrome from 'sinon-chrome';
+/**
+ * Internal dependencies.
+ */
+import parseHeaders from '../parseHeaders';
+//@ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
+
+describe('parseHeaders: ', () => {
+ beforeAll(() => {
+ jest.useFakeTimers().setSystemTime(new Date('2020-01-01'));
+ globalThis.chrome = {
+ ...(SinonChrome as unknown as typeof chrome),
+ //@ts-ignore
+ tabs: {
+ reload: jest.fn(),
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ query: (_, __) => {
+ return [{ id: 40245632, url: 'https://edition.cnn.com' }];
+ },
+ },
+ };
+
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...PSInfo,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('should not process request headers', async () => {
+ const cookies = await parseHeaders(
+ false,
+ 'request',
+ '123456',
+ 'single',
+ 12345,
+ 'https://cnn.com',
+ {},
+ 'https://cnn.com',
+ 0,
+ '123456',
+ [
+ {
+ name: 'name',
+ value: 'mkdes.pl',
+ },
+ {
+ name: 'Accept',
+ value:
+ 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+ },
+ {
+ name: 'cookie',
+ value:
+ 'cc_cookie={"categories":["ccat_functionality_storage","ccat_security_storage","ccat_analytics_storage","ccat_ad_storage","ccat_ad_user_data","ccat_ad_personalization","ccat_personalization_storage"],"level":["ccat_functionality_storage","ccat_security_storage","ccat_analytics_storage","ccat_ad_storage","ccat_ad_user_data","ccat_ad_personalization","ccat_personalization_storage"],"revision":0,"data":null,"rfc_cookie":false,"consent_date":"2024-02-21T10:25:39.063Z","consent_uuid":"7c4da0cf-3eb4-468a-91b0-a93a6a24cc59","last_consent_update":"2024-02-21T10:25:39.063Z"}; _ga=GA1.1.253380838.1708511136; _ga_FJBF08S8GG=GS1.1.1708580521.2.1.1708580783.60.0.1679255760',
+ },
+ ]
+ );
+
+ const cookies2 = await parseHeaders(
+ false,
+ 'request',
+ '123456',
+ 'single',
+ 12345,
+ 'https://cnn.com',
+ {},
+ 'https://cnn.com',
+ 0,
+ '123456'
+ );
+
+ const cookies3 = await parseHeaders(
+ false,
+ 'request',
+ '123456',
+ 'single',
+ 123456,
+ 'https://cnn.com',
+ {},
+ 'https://cnn.com',
+ 0,
+ '123456'
+ );
+
+ expect(cookies).toStrictEqual(null);
+ expect(cookies2).toStrictEqual(null);
+ expect(cookies3).toStrictEqual(null);
+ });
+
+ it('should process request headers', async () => {
+ const timeStamp = 1577836800000;
+
+ const cookies = await parseHeaders(
+ false,
+ 'request',
+ '123456',
+ 'single',
+ 123456,
+ 'https://cnn.com',
+ {},
+ 'https://cnn.com',
+ 0,
+ '123456',
+ [
+ {
+ name: 'name',
+ value: 'mkdes.pl',
+ },
+ {
+ name: 'Accept',
+ value:
+ 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
+ },
+ {
+ name: 'cookie',
+ value:
+ 'cc_cookie={"categories":["ccat_functionality_storage","ccat_security_storage","ccat_analytics_storage","ccat_ad_storage","ccat_ad_user_data","ccat_ad_personalization","ccat_personalization_storage"],"level":["ccat_functionality_storage","ccat_security_storage","ccat_analytics_storage","ccat_ad_storage","ccat_ad_user_data","ccat_ad_personalization","ccat_personalization_storage"],"revision":0,"data":null,"rfc_cookie":false,"consent_date":"2024-02-21T10:25:39.063Z","consent_uuid":"7c4da0cf-3eb4-468a-91b0-a93a6a24cc59","last_consent_update":"2024-02-21T10:25:39.063Z"}; _ga=GA1.1.253380838.1708511136; _ga_FJBF08S8GG=GS1.1.1708580521.2.1.1708580783.60.0.1679255760',
+ },
+ ]
+ );
+
+ expect(cookies).toStrictEqual([
+ {
+ analytics: {
+ category: 'Uncategorized',
+ dataController: '',
+ description: '',
+ domain: '',
+ gdprUrl: '',
+ name: '',
+ platform: '',
+ retention: '',
+ wildcard: '',
+ },
+ frameIdList: [0],
+ headerType: 'request',
+ isFirstParty: true,
+ networkEvents: {
+ requestEvents: [
+ {
+ blocked: false,
+ requestId: '123456',
+ timeStamp,
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ url: 'https://cnn.com',
+ },
+ ],
+ responseEvents: [],
+ },
+ parsedCookie: {
+ domain: '.cnn.com',
+ expires: 0,
+ httponly: false,
+ name: 'cc_cookie',
+ partitionKey: '',
+ path: '/',
+ priority: 'Medium',
+ samesite: '',
+ secure: false,
+ size: 570,
+ value:
+ '{"categories":["ccat_functionality_storage","ccat_security_storage","ccat_analytics_storage","ccat_ad_storage","ccat_ad_user_data","ccat_ad_personalization","ccat_personalization_storage"],"level":["ccat_functionality_storage","ccat_security_storage","ccat_analytics_storage","ccat_ad_storage","ccat_ad_user_data","ccat_ad_personalization","ccat_personalization_storage"],"revision":0,"data":null,"rfc_cookie":false,"consent_date":"2024-02-21T10:25:39.063Z","consent_uuid":"7c4da0cf-3eb4-468a-91b0-a93a6a24cc59","last_consent_update":"2024-02-21T10:25:39.063Z"}',
+ },
+ url: 'https://cnn.com',
+ },
+ {
+ analytics: {
+ category: 'Uncategorized',
+ dataController: '',
+ description: '',
+ domain: '',
+ gdprUrl: '',
+ name: '',
+ platform: '',
+ retention: '',
+ wildcard: '',
+ },
+ frameIdList: [0],
+ headerType: 'request',
+ isFirstParty: true,
+ networkEvents: {
+ requestEvents: [
+ {
+ blocked: false,
+ requestId: '123456',
+ timeStamp,
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ url: 'https://cnn.com',
+ },
+ ],
+ responseEvents: [],
+ },
+ parsedCookie: {
+ domain: '.cnn.com',
+ expires: 0,
+ httponly: false,
+ name: '_ga',
+ partitionKey: '',
+ path: '/',
+ priority: 'Medium',
+ samesite: '',
+ secure: false,
+ size: 29,
+ value: 'GA1.1.253380838.1708511136',
+ },
+ url: 'https://cnn.com',
+ },
+ {
+ analytics: {
+ category: 'Uncategorized',
+ dataController: '',
+ description: '',
+ domain: '',
+ gdprUrl: '',
+ name: '',
+ platform: '',
+ retention: '',
+ wildcard: '',
+ },
+ frameIdList: [0],
+ headerType: 'request',
+ isFirstParty: true,
+ networkEvents: {
+ requestEvents: [
+ {
+ blocked: false,
+ requestId: '123456',
+ timeStamp,
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ url: 'https://cnn.com',
+ },
+ ],
+ responseEvents: [],
+ },
+ parsedCookie: {
+ domain: '.cnn.com',
+ expires: 0,
+ httponly: false,
+ name: '_ga_FJBF08S8GG',
+ partitionKey: '',
+ path: '/',
+ priority: 'Medium',
+ samesite: '',
+ secure: false,
+ size: 61,
+ value: 'GS1.1.1708580521.2.1.1708580783.60.0.1679255760',
+ },
+ url: 'https://cnn.com',
+ },
+ ]);
+ });
+
+ it('should process response headers', async () => {
+ const cookies = await parseHeaders(
+ false,
+ 'response',
+ '123456',
+ 'single',
+ 123456,
+ 'https://cnn.com',
+ {},
+ 'https://cnn.com',
+ 0,
+ '123456',
+ [
+ {
+ name: 'name',
+ value: 'mkdes.pl',
+ },
+ {
+ name: 'Date',
+ value: 'Thu, 22 Feb 2024 07:59:33 GMT',
+ },
+ {
+ name: 'set-cookie',
+ value:
+ 'has_recent_activity=1; path=/; expires=Thu, 22 Feb 2024 08:59:32 GMT; secure; HttpOnly; SameSite=Lax',
+ },
+ {
+ name: 'Content-Type',
+ value: 'text/html; charset=utf-8',
+ },
+ ]
+ );
+
+ const timeStamp = 1577836800000;
+
+ expect(cookies).toStrictEqual([
+ {
+ analytics: {
+ category: 'Uncategorized',
+ dataController: '',
+ description: '',
+ domain: '',
+ gdprUrl: '',
+ name: '',
+ platform: '',
+ retention: '',
+ wildcard: '',
+ },
+ frameIdList: [0],
+ headerType: 'response',
+ isFirstParty: true,
+ networkEvents: {
+ requestEvents: [],
+ responseEvents: [
+ {
+ blocked: false,
+ requestId: '123456',
+ timeStamp,
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ url: 'https://cnn.com',
+ },
+ ],
+ },
+ parsedCookie: {
+ domain: 'cnn.com',
+ expires: '2024-02-22T08:59:32.000Z',
+ httponly: true,
+ name: 'has_recent_activity',
+ partitionKey: '',
+ path: '/',
+ priority: 'Medium',
+ samesite: 'lax',
+ secure: true,
+ size: 20,
+ value: '1',
+ },
+ url: 'https://cnn.com',
+ },
+ ]);
+ });
+});
diff --git a/packages/extension/src/utils/tests/reloadCurrentTab.ts b/packages/extension/src/utils/tests/reloadCurrentTab.ts
new file mode 100644
index 000000000..c767cc5fd
--- /dev/null
+++ b/packages/extension/src/utils/tests/reloadCurrentTab.ts
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import SinonChrome from 'sinon-chrome';
+/**
+ * Internal dependencies.
+ */
+import reloadCurrentTab from '../reloadCurrentTab';
+//@ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
+
+describe('reloadCurrentTab : ', () => {
+ beforeAll(() => {
+ globalThis.chrome = {
+ ...(SinonChrome as unknown as typeof chrome),
+ //@ts-ignore
+ tabs: {
+ reload: jest.fn(),
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ query: (_, __) => {
+ return [{ id: 40245632, url: 'https://edition.cnn.com' }];
+ },
+ },
+ };
+
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...PSInfo,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('should be called if tabId is passed', async () => {
+ await reloadCurrentTab(123);
+ expect(globalThis.chrome.tabs.reload).toHaveBeenCalled();
+ });
+
+ it('should be called if tabId is not passed passed', async () => {
+ await reloadCurrentTab();
+ expect(globalThis.chrome.tabs.reload).toHaveBeenLastCalledWith(40245632, {
+ bypassCache: true,
+ });
+ });
+});
diff --git a/packages/extension/src/view/devtools/app.tsx b/packages/extension/src/view/devtools/app.tsx
index 7eb26be8c..744da5d51 100644
--- a/packages/extension/src/view/devtools/app.tsx
+++ b/packages/extension/src/view/devtools/app.tsx
@@ -16,310 +16,67 @@
/**
* External dependencies.
*/
-import React, { useRef, useEffect, useCallback, useState } from 'react';
-import { Resizable } from 're-resizable';
+import React, { useRef, useEffect, useState } from 'react';
import {
- CookieIcon,
- CookieIconWhite,
ExtensionReloadNotification,
- Sidebar,
- useSidebar,
- type SidebarItems,
- InspectButton,
- ToastMessage,
+ SIDEBAR_ITEMS_KEYS,
+ SidebarProvider,
} from '@ps-analysis-tool/design-system';
-import { type CookieTableData } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
import TABS from './tabs';
-import { useCookieStore } from './stateProviders/syncCookieStore';
import './app.css';
-import { Cookies } from './components';
-import useFrameOverlay from './hooks/useFrameOverlay';
-import { getCurrentTabId } from '../../utils/getCurrentTabId';
-import { useSettingsStore } from './stateProviders/syncSettingsStore';
+import { Layout } from './components';
+import useContextInvalidated from './hooks/useContextInvalidated';
const App: React.FC = () => {
- const [sidebarWidth, setSidebarWidth] = useState(200);
const [sidebarData, setSidebarData] = useState(TABS);
const contextInvalidatedRef = useRef(null);
- const {
- contextInvalidated,
- setContextInvalidated,
- tabFrames,
- selectedFrame,
- setSelectedFrame,
- isInspecting,
- setIsInspecting,
- canStartInspecting,
- tabUrl,
- frameHasCookies,
- } = useCookieStore(({ state, actions }) => ({
- contextInvalidated: state.contextInvalidated,
- setContextInvalidated: actions.setContextInvalidated,
- tabCookies: state.tabCookies,
- tabFrames: state.tabFrames,
- selectedFrame: state.selectedFrame,
- setSelectedFrame: actions.setSelectedFrame,
- isInspecting: state.isInspecting,
- setIsInspecting: actions.setIsInspecting,
- canStartInspecting: state.canStartInspecting,
- tabUrl: state.tabUrl,
- frameHasCookies: state.frameHasCookies,
- }));
+ const tabIdRef = useRef(chrome.devtools.inspectedWindow.tabId);
- const mainRef = useRef(null);
- const toastMessageRef = useRef(null);
+ const contextInvalidated = useContextInvalidated(contextInvalidatedRef);
- const { allowedNumberOfTabs, settingsChanged, handleSettingsChange } =
- useSettingsStore(({ state, actions }) => ({
- allowedNumberOfTabs: state.allowedNumberOfTabs,
- settingsChanged: state.settingsChanged,
- handleSettingsChange: actions.handleSettingsChange,
- }));
-
- const listenToMouseChange = useCallback(() => {
- if (contextInvalidatedRef.current) {
- if (!chrome.runtime?.id) {
- setContextInvalidated(true);
- localStorage.setItem('contextInvalidated', 'true');
- }
- }
- }, [setContextInvalidated]);
-
- useEffect(() => {
- window.addEventListener('mouseover', listenToMouseChange);
-
- return () => {
- window.removeEventListener('mouseover', listenToMouseChange);
- };
- }, [listenToMouseChange]);
-
- const [defaultSelectedItemKey, setDefaultSelectedItemKey] =
- useState('privacySandbox');
-
- useEffect(() => {
- (async () => {
- const tabId = chrome.devtools.inspectedWindow.tabId.toString();
-
- const data = await chrome.storage.local.get();
-
- if (data?.[tabId]?.['selectedSidebarItem']) {
- setDefaultSelectedItemKey(data[tabId]['selectedSidebarItem']);
- }
- })();
- }, []);
-
- const {
- activePanel,
- selectedItemKey,
- currentItemKey,
- sidebarItems,
- isSidebarFocused,
- setIsSidebarFocused,
- updateSelectedItemKey,
- onKeyNavigation,
- toggleDropdown,
- isKeyAncestor,
- isKeySelected,
- } = useSidebar({
- data: sidebarData,
- defaultSelectedItemKey,
- });
-
- useEffect(() => {
- setSidebarData((prev) => {
- const data = { ...prev };
- const psData = data['privacySandbox'];
-
- psData.children['cookies'].panel = (
-
- );
- psData.children['cookies'].children = Object.keys(
- tabFrames || {}
- ).reduce((acc, url) => {
- const popupTitle = `Cookies used by frames from ${url}`;
-
- acc[url] = {
- title: url,
- popupTitle,
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {},
- isBlurred: !frameHasCookies?.[url],
- };
-
- return acc;
- }, {});
-
- const showInspectButton =
- canStartInspecting && Boolean(Object.keys(tabFrames || {}).length);
-
- if (showInspectButton) {
- psData.children['cookies'].extraInterfaceToTitle = (
-
- );
- } else {
- psData.children['cookies'].extraInterfaceToTitle = null;
- }
-
- return data;
- });
- }, [
- canStartInspecting,
- frameHasCookies,
- isInspecting,
- isKeySelected,
- isSidebarFocused,
- setIsInspecting,
- tabFrames,
- ]);
-
- useEffect(() => {
- if (Object.keys(tabFrames || {}).includes(currentItemKey || '')) {
- setSelectedFrame(currentItemKey);
- } else {
- setSelectedFrame(null);
- }
- }, [currentItemKey, setSelectedFrame, tabFrames]);
+ const [defaultSelectedItemKey, setDefaultSelectedItemKey] = useState(
+ SIDEBAR_ITEMS_KEYS.PRIVACY_SANDBOX
+ );
useEffect(() => {
(async () => {
- const tabId = chrome.devtools.inspectedWindow.tabId.toString();
-
- const data = await chrome.storage.local.get();
-
- if (!data?.[tabId]) {
- data[tabId] = {};
- }
+ const tabId = chrome.devtools.inspectedWindow.tabId;
- if (!data[tabId]?.['selectedSidebarItem']) {
- data[tabId]['selectedSidebarItem'] = 'cookies';
+ if (!tabId) {
+ return;
}
- data[tabId]['selectedSidebarItem'] = selectedItemKey;
-
- await chrome.storage.local.set(data);
- })();
- }, [selectedItemKey]);
-
- const lastUrl = useRef(tabUrl);
-
- useEffect(() => {
- if (lastUrl.current === tabUrl || lastUrl.current === null) {
- lastUrl.current = tabUrl;
- return;
- }
+ const data = await chrome.storage.session.get();
- lastUrl.current = tabUrl;
-
- updateSelectedItemKey(selectedFrame || 'cookies');
- }, [selectedFrame, tabUrl, updateSelectedItemKey]);
-
- const [filteredCookies, setFilteredCookies] = useState([]);
-
- const handleUpdate = useCallback(
- (key: string | null) => {
- updateSelectedItemKey(key || 'cookies');
- },
- [updateSelectedItemKey]
- );
-
- useEffect(() => {
- (async () => {
- const localStorageFlag = localStorage.getItem('contextInvalidated');
-
- if (
- localStorageFlag &&
- localStorageFlag === 'true' &&
- allowedNumberOfTabs === 'unlimited'
- ) {
- const tabId = await getCurrentTabId();
-
- if (tabId) {
- chrome.tabs.reload(Number(tabId));
- localStorage.removeItem('contextInvalidated');
- }
+ if (data?.['selectedSidebarItem#' + tabId]) {
+ setDefaultSelectedItemKey(data['selectedSidebarItem#' + tabId]);
}
})();
- }, [allowedNumberOfTabs]);
-
- useFrameOverlay(filteredCookies, handleUpdate);
+ }, []);
return (
-
- {contextInvalidated && (
-
-
-
- )}
- {!contextInvalidated && (
-
-
{
- setSidebarWidth((prevState) => prevState + d.width);
- }}
- minWidth={'150px'}
- maxWidth={'90%'}
- enable={{
- right: true,
- }}
- className="h-full"
- >
-
-
-
{
- if (mainRef.current && toastMessageRef.current) {
- toastMessageRef.current.style.bottom =
- '-' + mainRef.current.scrollTop + 'px';
- }
- }}
- className="h-full flex-1 relative overflow-hidden flex flex-col"
- >
-
-
- {settingsChanged && (
-
- )}
-
-
-
- )}
-
+
+ {!contextInvalidated ? (
+
+ ) : (
+
+
+
+ )}
+
+
);
};
diff --git a/packages/extension/src/view/devtools/components/antiCovertTracking/tests/index.tsx b/packages/extension/src/view/devtools/components/antiCovertTracking/tests/index.tsx
new file mode 100644
index 000000000..e6c1c599a
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/antiCovertTracking/tests/index.tsx
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import SinonChrome from 'sinon-chrome';
+/**
+ * Internal dependencies
+ */
+import BounceTracking from '../bounceTracking';
+import Fingerprinting from '../fingerprinting';
+import AntiCovertTracking from '../antiCovertTracking';
+//@ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
+import { act } from 'react-dom/test-utils';
+
+describe('AntiCovertTracking Landing Pages', () => {
+ beforeAll(() => {
+ globalThis.chrome = SinonChrome as unknown as typeof chrome;
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...PSInfo,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('should render BounceTracking', async () => {
+ act(() => {
+ render( );
+ });
+ expect(
+ await screen.findByTestId('bounce-tracking-content')
+ ).toBeInTheDocument();
+ });
+
+ it('should render Fingerprinting', async () => {
+ act(() => {
+ render( );
+ });
+
+ expect(
+ await screen.findByTestId('fingerprinting-content')
+ ).toBeInTheDocument();
+ });
+
+ it('should render AntiCovertTracking', async () => {
+ act(() => {
+ render( );
+ });
+ expect(await screen.findByText('Tracking Protection')).toBeInTheDocument();
+ });
+});
diff --git a/packages/extension/src/view/devtools/components/cookies/cookieLanding/blockedCookiesSection.tsx b/packages/extension/src/view/devtools/components/cookies/cookieLanding/blockedCookiesSection.tsx
new file mode 100644
index 000000000..7d23d0054
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/cookies/cookieLanding/blockedCookiesSection.tsx
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ CookiesLandingWrapper,
+ type DataMapping,
+ prepareCookieStatsComponents,
+ prepareCookiesCount,
+ MatrixContainer,
+ type MatrixComponentProps,
+ LEGEND_DESCRIPTION,
+ useFiltersMapping,
+ SIDEBAR_ITEMS_KEYS,
+ useSidebar,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useCookie, useSettings } from '../../../stateProviders';
+
+const BlockedCookiesSection = () => {
+ const { tabCookies, tabFrames } = useCookie(({ state }) => ({
+ tabCookies: state.tabCookies,
+ tabFrames: state.tabFrames,
+ }));
+
+ const { isUsingCDP } = useSettings(({ state }) => ({
+ isUsingCDP: state.isUsingCDP,
+ }));
+
+ // Callback selecting/updating the clicked item in the sidebar
+ const updateSelectedItemKey = useSidebar(
+ ({ actions }) => actions.updateSelectedItemKey
+ );
+
+ // For opening Cookies table with pre-filtered data, uses updateSelectedItemKey from useSidebar internally
+ const { selectedItemUpdater } = useFiltersMapping(tabFrames || {});
+
+ const cookieStats = prepareCookiesCount(tabCookies);
+ const cookiesStatsComponents = prepareCookieStatsComponents(cookieStats);
+ const blockedCookieDataMapping: DataMapping[] = [
+ {
+ title: 'Blocked cookies',
+ count: cookieStats.blockedCookies.total,
+ data: cookiesStatsComponents.blocked,
+ onClick:
+ cookieStats.blockedCookies.total > 0
+ ? () => selectedItemUpdater('All', 'blockedReasons')
+ : null,
+ },
+ ];
+ const dataComponents: MatrixComponentProps[] =
+ cookiesStatsComponents.blockedCookiesLegend.map((component) => {
+ const legendDescription = LEGEND_DESCRIPTION[component.label] || '';
+ return {
+ ...component,
+ description: legendDescription,
+ title: component.label,
+ containerClasses: '',
+ onClick: (title: string) =>
+ selectedItemUpdater(title, 'blockedReasons'),
+ };
+ });
+
+ const description = !isUsingCDP ? (
+ <>
+ Enable PSAT to use CDP via the{' '}
+ {
+ document
+ .getElementById('cookies-landing-scroll-container')
+ ?.scrollTo(0, 0);
+ updateSelectedItemKey(SIDEBAR_ITEMS_KEYS.SETTINGS);
+ }}
+ >
+ Settings page
+
+ .
+ For more information, visit the PSAT
+
+ Wiki
+
+ .
+ >
+ ) : (
+ ''
+ );
+
+ return (
+
+ {dataComponents.length > 0 && (
+
+ )}
+
+ );
+};
+export default BlockedCookiesSection;
diff --git a/packages/extension/src/view/devtools/components/cookies/cookieLanding/cookiesSection.tsx b/packages/extension/src/view/devtools/components/cookies/cookieLanding/cookiesSection.tsx
new file mode 100644
index 000000000..c8699df32
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/cookies/cookieLanding/cookiesSection.tsx
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React, { useMemo } from 'react';
+import {
+ CookiesLandingWrapper,
+ CookiesMatrix,
+ MessageBox,
+ prepareCookieDataMapping,
+ prepareCookieStatsComponents,
+ prepareCookiesCount,
+ useFiltersMapping,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useCookie } from '../../../stateProviders';
+
+const CookiesSection = () => {
+ const { tabCookies, tabFrames } = useCookie(({ state }) => ({
+ tabCookies: state.tabCookies,
+ tabFrames: state.tabFrames,
+ }));
+
+ const { selectedItemUpdater } = useFiltersMapping(tabFrames || {});
+
+ const cookieStats = prepareCookiesCount(tabCookies);
+ const cookiesStatsComponents = prepareCookieStatsComponents(cookieStats);
+ const cookieClassificationDataMapping = prepareCookieDataMapping(
+ cookieStats,
+ cookiesStatsComponents,
+ selectedItemUpdater
+ );
+
+ const cookieComponentData = useMemo(() => {
+ return cookiesStatsComponents.legend.map((component) => ({
+ ...component,
+ onClick: (title: string) =>
+ selectedItemUpdater(title, 'analytics.category'),
+ }));
+ }, [cookiesStatsComponents.legend, selectedItemUpdater]);
+
+ const processedTabFrames = useMemo(
+ () => Object.fromEntries(Object.entries(tabFrames || {})),
+ [tabFrames]
+ );
+
+ return (
+
+ Please setup the{' '}
+
+ evaluation environment
+ {' '}
+ before analyzing cookies.
+ >
+ }
+ testId="cookies-insights"
+ >
+ {!cookieStats ||
+ (cookieStats?.firstParty.total === 0 &&
+ cookieStats?.thirdParty.total === 0 && (
+
+ ))}
+
+
+ );
+};
+export default CookiesSection;
diff --git a/packages/extension/src/view/devtools/components/cookies/cookieLanding/exemptedCookiesSection.tsx b/packages/extension/src/view/devtools/components/cookies/cookieLanding/exemptedCookiesSection.tsx
new file mode 100644
index 000000000..fe5c450da
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/cookies/cookieLanding/exemptedCookiesSection.tsx
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ prepareCookieStatsComponents,
+ prepareCookiesCount,
+ type DataMapping,
+ useFiltersMapping,
+ MatrixContainer,
+ CookiesLandingWrapper,
+ type MatrixComponentProps,
+ LEGEND_DESCRIPTION,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useSettings, useCookie } from '../../../stateProviders';
+
+const ExemptedCookiesSection = () => {
+ const { tabCookies, tabFrames } = useCookie(({ state }) => ({
+ tabCookies: state.tabCookies,
+ tabFrames: state.tabFrames,
+ }));
+
+ const { isUsingCDP } = useSettings(({ state }) => ({
+ isUsingCDP: state.isUsingCDP,
+ }));
+
+ const { selectedItemUpdater } = useFiltersMapping(tabFrames || {});
+
+ const cookieStats = prepareCookiesCount(tabCookies);
+ const cookiesStatsComponents = prepareCookieStatsComponents(cookieStats);
+
+ const dataComponents: MatrixComponentProps[] =
+ cookiesStatsComponents.exemptedCookiesLegend.map((component) => {
+ const legendDescription = LEGEND_DESCRIPTION[component.label] || '';
+ return {
+ ...component,
+ description: legendDescription,
+ title: component.label,
+ containerClasses: '',
+ onClick: (title: string) => {
+ selectedItemUpdater(title, 'exemptionReason');
+ },
+ };
+ });
+ const exemptedCookiesDataMapping: DataMapping[] = [
+ {
+ title: 'Exempted cookies',
+ count: cookieStats.exemptedCookies.total,
+ data: cookiesStatsComponents.exempted,
+ onClick: () => selectedItemUpdater('All', 'exemptionReason'),
+ },
+ ];
+
+ const description = !isUsingCDP ? (
+ <>
+ To gather data and insights regarding blocked cookies and exempted
+ cookies, please enable PSAT to use the Chrome DevTools protocol. You can
+ do this in the Settings page or in the extension popup. For more
+ information check the PSAT
+
+ Wiki
+
+ >
+ ) : (
+ ''
+ );
+
+ return (
+
+ {dataComponents.length > 0 && (
+
+ )}
+
+ );
+};
+export default ExemptedCookiesSection;
diff --git a/packages/extension/src/view/devtools/components/cookies/cookieLanding/framesSection.tsx b/packages/extension/src/view/devtools/components/cookies/cookieLanding/framesSection.tsx
new file mode 100644
index 000000000..820af36d3
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/cookies/cookieLanding/framesSection.tsx
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ CookiesLandingWrapper,
+ MatrixContainer,
+ prepareFrameStatsComponent,
+ type MatrixComponentProps,
+ LEGEND_DESCRIPTION,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useCookie } from '../../../stateProviders';
+
+const FramesSection = () => {
+ const { tabCookies, tabFrames } = useCookie(({ state }) => ({
+ tabCookies: state.tabCookies,
+ tabFrames: state.tabFrames,
+ }));
+
+ const framesStats = prepareFrameStatsComponent(tabFrames, tabCookies);
+ const dataComponents: MatrixComponentProps[] = framesStats.legend.map(
+ (component) => {
+ const legendDescription = LEGEND_DESCRIPTION[component.label] || '';
+ return {
+ ...component,
+ description: legendDescription,
+ title: component.label,
+ containerClasses: '',
+ };
+ }
+ );
+
+ return (
+
+
+
+ );
+};
+export default FramesSection;
diff --git a/packages/extension/src/view/devtools/components/cookies/cookieLanding/index.tsx b/packages/extension/src/view/devtools/components/cookies/cookieLanding/index.tsx
new file mode 100644
index 000000000..b573a2112
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/cookies/cookieLanding/index.tsx
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React, { useMemo } from 'react';
+import {
+ LibraryDetection,
+ useLibraryDetectionContext,
+} from '@ps-analysis-tool/library-detection';
+import {
+ MenuBar,
+ type CookiesLandingSection,
+ type MenuData,
+ prepareCookiesCount,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import CookiesSection from './cookiesSection';
+import FramesSection from './framesSection';
+import BlockedCookiesSection from './blockedCookiesSection';
+import { useCookie } from '../../../stateProviders';
+import downloadReport from '../../../../../utils/downloadReport';
+import ExemptedCookiesSection from './exemptedCookiesSection';
+
+const AssembledCookiesLanding = () => {
+ const { url, tabCookies, tabFrames } = useCookie(({ state }) => ({
+ tabCookies: state.tabCookies,
+ tabFrames: state.tabFrames,
+ url: state.tabUrl,
+ }));
+
+ const { libraryMatches, showLoader } = useLibraryDetectionContext(
+ ({ state }) => ({
+ libraryMatches: state.libraryMatches,
+ showLoader: state.showLoader,
+ })
+ );
+
+ const cookieStats = prepareCookiesCount(tabCookies);
+ const sections: Array = useMemo(() => {
+ const defaultSections = [
+ {
+ name: 'Cookies',
+ link: 'cookies',
+ panel: {
+ Element: CookiesSection,
+ },
+ },
+ {
+ name: 'Blocked Cookies',
+ link: 'blocked-cookies',
+ panel: {
+ Element: BlockedCookiesSection,
+ },
+ },
+ {
+ name: 'Library Detection',
+ link: 'library-detection',
+ panel: {
+ Element: LibraryDetection,
+ },
+ },
+ {
+ name: 'Frames',
+ link: 'frames',
+ panel: {
+ Element: FramesSection,
+ },
+ },
+ ];
+ if (cookieStats.exemptedCookies.total > 0) {
+ defaultSections.splice(2, 0, {
+ name: 'Exemption Reason',
+ link: 'exemption-reasons',
+ panel: {
+ Element: ExemptedCookiesSection,
+ },
+ });
+ }
+ return defaultSections;
+ }, [cookieStats.exemptedCookies.total]);
+
+ const menuData: MenuData = useMemo(
+ () => sections.map(({ name, link }) => ({ name, link })),
+ [sections]
+ );
+
+ return (
+ <>
+ {
+ if (tabCookies && tabFrames && libraryMatches && url) {
+ downloadReport(url, tabCookies, tabFrames, libraryMatches);
+ }
+ }}
+ menuData={menuData}
+ scrollContainerId="cookies-landing-scroll-container"
+ />
+ {sections.map(({ link, panel: { Element, props } }) => (
+
+ {Element && }
+
+ ))}
+ >
+ );
+};
+export default AssembledCookiesLanding;
diff --git a/packages/extension/src/view/devtools/components/cookies/cookiesListing/index.tsx b/packages/extension/src/view/devtools/components/cookies/cookiesListing/index.tsx
index a8c00301a..e45c64cb7 100644
--- a/packages/extension/src/view/devtools/components/cookies/cookiesListing/index.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/cookiesListing/index.tsx
@@ -27,24 +27,23 @@ import { CookieDetails, CookieTable } from '@ps-analysis-tool/design-system';
/**
* Internal dependencies.
*/
-import { useCookieStore } from '../../../stateProviders/syncCookieStore';
+import { useCookie, useSettings } from '../../../stateProviders';
import useCookieListing from './useCookieListing';
import RowContextMenu from './rowContextMenu';
-import { useSettingsStore } from '../../../stateProviders/syncSettingsStore';
-import { useAllowedList } from '../../../stateProviders/useAllowedList';
+import { useAllowedList } from '../../../stateProviders/allowedList';
interface CookiesListingProps {
setFilteredCookies: React.Dispatch;
}
const CookiesListing = ({ setFilteredCookies }: CookiesListingProps) => {
- const { selectedFrame, tabFrames, tabUrl } = useCookieStore(({ state }) => ({
+ const { selectedFrame, tabFrames, tabUrl } = useCookie(({ state }) => ({
selectedFrame: state.selectedFrame,
tabFrames: state.tabFrames,
tabUrl: state.tabUrl,
}));
- const isUsingCDP = useSettingsStore(({ state }) => state.isUsingCDP);
+ const isUsingCDP = useSettings(({ state }) => state.isUsingCDP);
const { domainsInAllowList, setDomainsInAllowListCallback, isIncognito } =
useAllowedList(({ state, actions }) => ({
@@ -60,6 +59,7 @@ const CookiesListing = ({ setFilteredCookies }: CookiesListingProps) => {
searchKeys,
tablePersistentSettingsKey,
extraInterfaceToTopBar,
+ isSidebarOpen,
} = useCookieListing(domainsInAllowList);
const frameFilteredCookies = useMemo(
@@ -100,13 +100,13 @@ const CookiesListing = ({ setFilteredCookies }: CookiesListingProps) => {
className="h-full flex"
>
;
@@ -139,7 +139,7 @@ const RowContextMenu = forwardRef<
setDomainsInAllowListCallback
);
setContextMenuOpen(false);
- await reloadCurrentTab();
+ await reloadCurrentTab(chrome.devtools.inspectedWindow.tabId);
},
[
dotPrefixedDomain,
@@ -165,7 +165,7 @@ const RowContextMenu = forwardRef<
setDomainsInAllowListCallback
);
setContextMenuOpen(false);
- await reloadCurrentTab();
+ await reloadCurrentTab(chrome.devtools.inspectedWindow.tabId);
},
[
domainsInAllowList,
diff --git a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/index.tsx b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/index.tsx
index 38f818ff2..0f6c293bc 100644
--- a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/index.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/index.tsx
@@ -17,9 +17,8 @@
/**
* External dependencies
*/
-import React, { useMemo, useState } from 'react';
+import React, { useCallback, useMemo, useState } from 'react';
import {
- getValueByKey,
type CookieTableData,
type TabCookies,
BLOCK_STATUS,
@@ -30,21 +29,26 @@ import {
type TableColumn,
type TableFilter,
type TableRow,
+ useSidebar,
+ calculateDynamicFilterValues,
+ evaluateStaticFilterValues,
+ evaluateSelectAllOption,
+ calculateBlockedReasonsFilterValues,
type TableData,
InfoIcon,
+ calculateExemptionReason,
} from '@ps-analysis-tool/design-system';
/**
* Internal dependencies
*/
-import { useCookieStore } from '../../../../stateProviders/syncCookieStore';
+import { useCookie, useSettings } from '../../../../stateProviders';
import useHighlighting from './useHighlighting';
-import { useSettingsStore } from '../../../../stateProviders/syncSettingsStore';
-import namePrefixIconSelector from './namePrefixIconSelector';
+import NamePrefixIconSelector from './namePrefixIconSelector';
import OrphanedUnMappedInfoDisplay from './orphanedUnMappedInfoDisplay';
const useCookieListing = (domainsInAllowList: Set) => {
- const { selectedFrame, cookies, getCookiesSetByJavascript } = useCookieStore(
+ const { selectedFrame, cookies, getCookiesSetByJavascript } = useCookie(
({ state, actions }) => ({
selectedFrame: state.selectedFrame,
cookies: state.tabCookies || {},
@@ -52,7 +56,19 @@ const useCookieListing = (domainsInAllowList: Set) => {
})
);
- const isUsingCDP = useSettingsStore(({ state }) => state.isUsingCDP);
+ const { activePanelQuery, clearActivePanelQuery } = useSidebar(
+ ({ state }) => ({
+ activePanelQuery: state.activePanel.query,
+ clearActivePanelQuery: state.activePanel.clearQuery,
+ })
+ );
+
+ const parsedQuery = useMemo(
+ () => JSON.parse(activePanelQuery || '{}'),
+ [activePanelQuery]
+ );
+
+ const isUsingCDP = useSettings(({ state }) => state.isUsingCDP);
const [tableData, setTableData] = useState(cookies);
@@ -67,7 +83,9 @@ const useCookieListing = (domainsInAllowList: Set) => {
enableHiding: false,
widthWeightagePercentage: 13,
enableBodyCellPrefixIcon: isUsingCDP,
- bodyCellPrefixIcon: namePrefixIconSelector,
+ bodyCellPrefixIcon: {
+ Element: NamePrefixIconSelector,
+ },
showBodyCellPrefixIcon: (row: TableRow) => {
const isBlocked = Boolean(
(row.originalData as CookieTableData)?.blockingStatus
@@ -163,12 +181,14 @@ const useCookieListing = (domainsInAllowList: Set) => {
{
header: 'Priority',
accessorKey: 'parsedCookie.priority',
+ isHiddenByDefault: true,
cell: (info: InfoType) => info,
widthWeightagePercentage: 4,
},
{
header: 'Size',
accessorKey: 'parsedCookie.size',
+ isHiddenByDefault: true,
cell: (info: InfoType) => info,
widthWeightagePercentage: 3,
},
@@ -216,8 +236,6 @@ const useCookieListing = (domainsInAllowList: Set) => {
Undetermined
);
- } else if (hasValidBlockedReason) {
- return Blocked ;
} else {
return <>>;
}
@@ -227,81 +245,38 @@ const useCookieListing = (domainsInAllowList: Set) => {
[isUsingCDP]
);
- const preCalculatedFilters = useMemo<{
- category: TableFilter[keyof TableFilter]['filterValues'];
- platform: TableFilter[keyof TableFilter]['filterValues'];
- blockedReason: TableFilter[keyof TableFilter]['filterValues'];
- }>(() => {
- const calculate = (
- key: string
- ): TableFilter[keyof TableFilter]['filterValues'] =>
- Object.values(cookies).reduce((acc, cookie) => {
- const value = getValueByKey(key, cookie);
-
- if (!acc) {
- acc = {};
- }
-
- if (value) {
- acc[value] = {
- selected: false,
- };
- }
-
- return acc;
- }, {} as TableFilter[keyof TableFilter]['filterValues']);
-
- const blockedReasonFilterValues = Object.values(cookies).reduce(
- (acc, cookie) => {
- const blockedReason = getValueByKey('blockedReasons', cookie);
-
- if (!cookie.frameIdList || cookie?.frameIdList?.length === 0) {
- return acc;
- }
-
- blockedReason?.forEach((reason: string) => {
- if (!acc) {
- acc = {};
- }
-
- acc[reason] = {
- selected: false,
- };
- });
-
- return acc;
- },
- {} as TableFilter[keyof TableFilter]['filterValues']
- );
-
- return {
- category: calculate('analytics.category'),
- platform: calculate('analytics.platform'),
- blockedReason: blockedReasonFilterValues,
- };
- }, [cookies]);
-
const filters = useMemo(
() => ({
'analytics.category': {
title: 'Category',
hasStaticFilterValues: true,
hasPrecalculatedFilterValues: true,
- filterValues: preCalculatedFilters.category,
+ filterValues: calculateDynamicFilterValues(
+ 'analytics.category',
+ Object.values(cookies),
+ parsedQuery?.filter?.['analytics.category'],
+ clearActivePanelQuery
+ ),
sortValues: true,
useGenericPersistenceKey: true,
},
isFirstParty: {
title: 'Scope',
hasStaticFilterValues: true,
- filterValues: {
- 'First Party': {
- selected: false,
- },
- 'Third Party': {
- selected: false,
+ hasPrecalculatedFilterValues: true,
+ filterValues: evaluateStaticFilterValues(
+ {
+ 'First Party': {
+ selected: false,
+ },
+ 'Third Party': {
+ selected: false,
+ },
},
- },
+ 'isFirstParty',
+ parsedQuery,
+ clearActivePanelQuery
+ ),
useGenericPersistenceKey: true,
comparator: (value: InfoType, filterValue: string) => {
const val = Boolean(value);
@@ -421,7 +396,12 @@ const useCookieListing = (domainsInAllowList: Set) => {
title: 'Platform',
hasStaticFilterValues: true,
hasPrecalculatedFilterValues: true,
- filterValues: preCalculatedFilters.platform,
+ filterValues: calculateDynamicFilterValues(
+ 'analytics.platform',
+ Object.values(cookies),
+ parsedQuery?.filter?.['analytics.platform'],
+ clearActivePanelQuery
+ ),
sortValues: true,
useGenericPersistenceKey: true,
},
@@ -430,7 +410,15 @@ const useCookieListing = (domainsInAllowList: Set) => {
hasStaticFilterValues: true,
hasPrecalculatedFilterValues: true,
enableSelectAllOption: true,
- filterValues: preCalculatedFilters.blockedReason,
+ isSelectAllOptionSelected: evaluateSelectAllOption(
+ 'blockedReasons',
+ parsedQuery
+ ),
+ filterValues: calculateBlockedReasonsFilterValues(
+ Object.values(cookies),
+ parsedQuery?.filter?.blockedReasons,
+ clearActivePanelQuery
+ ),
sortValues: true,
useGenericPersistenceKey: true,
comparator: (value: InfoType, filterValue: string) => {
@@ -494,12 +482,28 @@ const useCookieListing = (domainsInAllowList: Set) => {
},
useGenericPersistenceKey: true,
},
+ exemptionReason: {
+ title: 'Exemption Reason',
+ hasStaticFilterValues: true,
+ hasPrecalculatedFilterValues: true,
+ enableSelectAllOption: true,
+ isSelectAllOptionSelected: evaluateSelectAllOption(
+ 'exemptionReason',
+ parsedQuery
+ ),
+ filterValues: calculateExemptionReason(
+ Object.values(cookies),
+ clearActivePanelQuery,
+ parsedQuery?.filter?.exemptionReason
+ ),
+ comparator: (value: InfoType, filterValue: string) => {
+ const val = value as string;
+ return val === filterValue;
+ },
+ useGenericPersistenceKey: true,
+ },
}),
- [
- preCalculatedFilters.blockedReason,
- preCalculatedFilters.category,
- preCalculatedFilters.platform,
- ]
+ [clearActivePanelQuery, cookies, parsedQuery]
);
const searchKeys = useMemo(
@@ -515,7 +519,7 @@ const useCookieListing = (domainsInAllowList: Set) => {
return `cookieListing#${selectedFrame}`;
}, [selectedFrame]);
- const extraInterfaceToTopBar = useMemo(() => {
+ const extraInterfaceToTopBar = useCallback(() => {
return (
) => {
searchKeys,
tablePersistentSettingsKey,
extraInterfaceToTopBar,
+ isSidebarOpen: parsedQuery?.filter ? true : false,
};
};
diff --git a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/namePrefixIconSelector.tsx b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/namePrefixIconSelector.tsx
index ed61dd6e0..9bb02a872 100644
--- a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/namePrefixIconSelector.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/namePrefixIconSelector.tsx
@@ -20,7 +20,6 @@
import React from 'react';
import { BLOCK_STATUS, type CookieTableData } from '@ps-analysis-tool/common';
import {
- type TableRow,
GreenTick,
InboundIcon,
OutboundIcon,
@@ -28,7 +27,13 @@ import {
OutboundInboundColoredIcon,
} from '@ps-analysis-tool/design-system';
-const namePrefixIconSelector = ({ originalData }: TableRow) => {
+interface NamePrefixIconSelectorProps {
+ originalData: CookieTableData;
+}
+
+const NamePrefixIconSelector = ({
+ originalData,
+}: NamePrefixIconSelectorProps) => {
const data = originalData as CookieTableData;
const isDomainInAllowList = data?.isDomainInAllowList;
@@ -88,4 +93,4 @@ const namePrefixIconSelector = ({ originalData }: TableRow) => {
return <>>;
};
-export default namePrefixIconSelector;
+export default NamePrefixIconSelector;
diff --git a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/orphanedUnMappedInfoDisplay.tsx b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/orphanedUnMappedInfoDisplay.tsx
index 7f00dce16..59852aca6 100644
--- a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/orphanedUnMappedInfoDisplay.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/orphanedUnMappedInfoDisplay.tsx
@@ -18,9 +18,13 @@
* External dependencies.
*/
import React from 'react';
-import { useCookieStore } from '../../../../stateProviders/syncCookieStore';
import { InfoIcon } from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useCookie } from '../../../../stateProviders';
+
interface OrphanedUnMappedInfoDisplayProps {
frameIdList: number[];
}
@@ -28,7 +32,7 @@ interface OrphanedUnMappedInfoDisplayProps {
const OrphanedUnMappedInfoDisplay = ({
frameIdList,
}: OrphanedUnMappedInfoDisplayProps) => {
- const tabFrames = useCookieStore(({ state }) => state.tabFrames);
+ const tabFrames = useCookie(({ state }) => state.tabFrames);
if (!tabFrames) {
return {''} ;
diff --git a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/tests/useCookieListing.tsx b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/tests/useCookieListing.tsx
index 4e96d0221..2dcfd1689 100644
--- a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/tests/useCookieListing.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/tests/useCookieListing.tsx
@@ -25,14 +25,15 @@ import { renderHook } from '@testing-library/react';
*/
import useCookieListing from '..';
import * as mock from '../../../../../../../utils/test-data/cookieMockData';
-import * as ChromeStorage from '../../../../../stateProviders/syncCookieStore';
+import { useCookie } from '../../../../../stateProviders/cookie';
-describe('useCookieListing', () => {
- const mockUseCookieStore = jest.fn();
- jest
- .spyOn(ChromeStorage, 'useCookieStore')
- .mockImplementation(mockUseCookieStore);
+jest.mock('../../../../../stateProviders/cookie', () => ({
+ useCookie: jest.fn(),
+}));
+
+const mockUseCookieStore = useCookie as jest.Mock;
+describe('useCookieListing', () => {
const mockUseEffect = jest.fn();
jest.spyOn(React, 'useEffect').mockImplementation(mockUseEffect);
@@ -56,7 +57,9 @@ describe('useCookieListing', () => {
selectedFrame: '',
});
- const { result, rerender } = renderHook(() => useCookieListing());
+ const { result, rerender } = renderHook(() =>
+ useCookieListing(new Set())
+ );
expect(result.current.tableColumns[0].header).toBe('Name');
expect(result.current.tableColumns[1].header).toBe('Scope');
diff --git a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/useHighlighting.tsx b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/useHighlighting.tsx
index 64b35cc90..d12a7eb38 100644
--- a/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/useHighlighting.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/cookiesListing/useCookieListing/useHighlighting.tsx
@@ -22,7 +22,7 @@ import { getCookieKey, type TabCookies } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import { isCookieDomainInAllowList } from '../../../../stateProviders/useAllowedList/utils';
+import { isCookieDomainInAllowList } from '../../../../stateProviders/allowedList/utils';
const useHighlighting = (
cookies: TabCookies,
@@ -52,6 +52,7 @@ const useHighlighting = (
if (Object.values(cookies).length > 0) {
return handleHighlighting(cookies);
}
+
return prevState;
});
}, [cookies, handleHighlighting, setTableData, domainsInAllowList?.size]);
diff --git a/packages/extension/src/view/devtools/components/cookies/index.tsx b/packages/extension/src/view/devtools/components/cookies/index.tsx
index c7448a020..f6ec6b029 100644
--- a/packages/extension/src/view/devtools/components/cookies/index.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/index.tsx
@@ -16,21 +16,20 @@
/**
* External dependencies.
*/
-import React, { useMemo } from 'react';
+import React from 'react';
import {
Button,
CookiesLanding,
ProgressBar,
} from '@ps-analysis-tool/design-system';
-import { LibraryDetection } from '@ps-analysis-tool/library-detection';
import { type CookieTableData } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import { useSettingsStore } from '../../stateProviders/syncSettingsStore';
-import { useCookieStore } from '../../stateProviders/syncCookieStore';
+import { useCookie, useSettings } from '../../stateProviders';
import CookiesListing from './cookiesListing';
+import AssembledCookiesLanding from './cookieLanding';
interface CookiesProps {
setFilteredCookies: React.Dispatch;
@@ -41,32 +40,20 @@ const Cookies = ({ setFilteredCookies }: CookiesProps) => {
isCurrentTabBeingListenedTo,
loading,
selectedFrame,
- tabCookies,
- tabFrames,
- changeListeningToThisTab,
tabToRead,
- } = useCookieStore(({ state, actions }) => ({
- tabToRead: state.tabToRead,
- contextInvalidated: state.contextInvalidated,
+ changeListeningToThisTab,
+ } = useCookie(({ state, actions }) => ({
isCurrentTabBeingListenedTo: state.isCurrentTabBeingListenedTo,
loading: state.loading,
- returningToSingleTab: state.returningToSingleTab,
selectedFrame: state.selectedFrame,
- tabCookies: state.tabCookies,
- tabFrames: state.tabFrames,
+ tabToRead: state.tabToRead,
changeListeningToThisTab: actions.changeListeningToThisTab,
}));
- const { allowedNumberOfTabs, isUsingCDP } = useSettingsStore(({ state }) => ({
+ const { allowedNumberOfTabs } = useSettings(({ state }) => ({
allowedNumberOfTabs: state.allowedNumberOfTabs,
- isUsingCDP: state.isUsingCDP,
}));
- const processedTabFrames = useMemo(
- () => Object.fromEntries(Object.entries(tabFrames || {})),
- [tabFrames]
- );
-
if (
loading ||
(loading &&
@@ -89,25 +76,6 @@ const Cookies = ({ setFilteredCookies }: CookiesProps) => {
allowedNumberOfTabs === 'single') ||
(allowedNumberOfTabs && allowedNumberOfTabs === 'unlimited')
) {
- const description = !isUsingCDP ? (
- <>
- To gather data and insights regarding blocked cookies, please enable
- PSAT to use the Chrome DevTools protocol. You can do this in the
- Settings page or in the extension popup. For more information check the
- PSAT
-
- Wiki
-
- >
- ) : (
- ''
- );
-
return (
{
{selectedFrame ? (
) : (
-
+
+
+
)}
);
diff --git a/packages/extension/src/view/devtools/components/cookies/tests/cookieTab.tsx b/packages/extension/src/view/devtools/components/cookies/tests/cookieTab.tsx
index 0a9686899..ee9ad49e3 100644
--- a/packages/extension/src/view/devtools/components/cookies/tests/cookieTab.tsx
+++ b/packages/extension/src/view/devtools/components/cookies/tests/cookieTab.tsx
@@ -26,8 +26,12 @@ import {
} from '@testing-library/react';
import '@testing-library/jest-dom';
import SinonChrome from 'sinon-chrome';
-import { CookieDetails, Details } from '@ps-analysis-tool/design-system';
-
+import {
+ CookieDetails,
+ Details,
+ useTablePersistentSettingsStore,
+} from '@ps-analysis-tool/design-system';
+import { noop } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
@@ -37,23 +41,23 @@ import mockResponse, {
known1pCookie,
known3pCookieWithValue,
} from '../../../../../utils/test-data/cookieMockData';
-import { noop } from '@ps-analysis-tool/common';
+import { useCookie, useSettings } from '../../../stateProviders';
-jest.mock('../../../stateProviders/syncCookieStore', () => {
- return {
- useCookieStore: () => {
- return {
- cookies: Object.values(mockResponse.tabCookies),
- tabFrames: mockResponse.tabFrames,
- selectedFrame: mockResponse.selectedFrame,
- isCurrentTabBeingListenedTo: true,
- allowedNumberOfTabs: 'single',
- loading: false,
- tabCookies: Object.values(mockResponse.tabCookies),
- };
- },
- };
-});
+jest.mock('../../../stateProviders', () => ({
+ useCookie: jest.fn(),
+ useSettings: jest.fn(),
+}));
+jest.mock(
+ '../../../../../../../design-system/src/components/table/persistentSettingsStore',
+ () => ({
+ useTablePersistentSettingsStore: jest.fn(),
+ })
+);
+
+const mockUseCookieStore = useCookie as jest.Mock;
+const mockUseSettingsStore = useSettings as jest.Mock;
+const mockUseTablePersistentSettingStore =
+ useTablePersistentSettingsStore as jest.Mock;
global.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
@@ -61,26 +65,78 @@ global.ResizeObserver = jest.fn().mockImplementation(() => ({
disconnect: jest.fn(),
}));
-describe.skip('CookieTab', () => {
+describe('CookieTab', () => {
beforeAll(() => {
globalThis.chrome = {
...(SinonChrome as unknown as typeof chrome),
storage: {
+ //@ts-ignore
+ local: {
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ get: (_, __) =>
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ new Promise<{ [key: string]: any }>((resolve) => {
+ resolve({
+ 40245632: {
+ selectedSidebarItem: 'privacySandbox#cookies',
+ tablePersistentSettingsStore: {
+ 'cookieListing#https://edition.cnn.com/': {
+ sortBy: 'parsedCookie.name',
+ sortOrder: 'asc',
+ },
+ },
+ },
+ tabToRead: '40245632',
+ });
+ }),
+ set: () => Promise.resolve(),
+ //@ts-ignore
+ onChanged: {
+ addListener: () => undefined,
+ removeListener: () => undefined,
+ },
+ },
// @ts-ignore
session: {
- // @ts-ignore
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ get: (_, __) => Promise.resolve(),
+ set: () => Promise.resolve(),
+ //@ts-ignore
onChanged: {
addListener: () => undefined,
removeListener: () => undefined,
},
},
+ devtools: {
+ inspectedWindow: {
+ tabId: 40245632,
+ },
+ },
},
};
-
+ globalThis.location.protocol = 'chrome-extension://absda';
globalThis.Promise = Promise;
});
it('should render a list of cookies with analytics', async () => {
+ mockUseTablePersistentSettingStore.mockReturnValue({
+ getPreferences: () => '',
+ setPreferences: noop,
+ });
+ mockUseCookieStore.mockReturnValue({
+ cookies: Object.values(mockResponse.tabCookies),
+ tabFrames: mockResponse.tabFrames,
+ selectedFrame: mockResponse.selectedFrame,
+ isCurrentTabBeingListenedTo: true,
+ tabToRead: '40245632',
+ loading: false,
+ tabCookies: Object.values(mockResponse.tabCookies),
+ });
+ mockUseSettingsStore.mockReturnValue({
+ allowedNumberOfTabs: 'single',
+ });
render( );
expect((await screen.findAllByTestId('body-row')).length).toBe(4);
@@ -191,7 +247,7 @@ describe.skip('CookieTab', () => {
});
it('should render a cookie card with placeholder text when no cookie is selected', async () => {
- render( );
+ render( );
expect(
await screen.findByText('Select cookies to preview its value')
@@ -201,6 +257,7 @@ describe.skip('CookieTab', () => {
it('should decode cookie value when input show URI decoded is checked', async () => {
render(
);
@@ -225,7 +282,12 @@ describe.skip('CookieTab', () => {
const firstCookie =
mockResponse.tabCookies[Object.keys(mockResponse.tabCookies)[0]];
- render( );
+ render(
+
+ );
const card = await screen.findByTestId('cookie-card');
expect(card).toBeInTheDocument();
@@ -238,6 +300,7 @@ describe.skip('CookieTab', () => {
it('should show a cookie card with the description about cookie', async () => {
render(
{
it('should show a cookie card with no description about cookie', async () => {
render(
{
render(
{
await within(card).findByText('known3p_Cookie-with value')
).toBeInTheDocument();
});
+ afterAll(() => {
+ jest.clearAllMocks();
+ });
});
diff --git a/packages/extension/src/view/devtools/components/cookies/tests/cookiesLanding.tsx b/packages/extension/src/view/devtools/components/cookies/tests/cookiesLanding.tsx
new file mode 100644
index 000000000..6015e6428
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/cookies/tests/cookiesLanding.tsx
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render } from '@testing-library/react';
+import '@testing-library/jest-dom/extend-expect';
+import SinonChrome from 'sinon-chrome';
+import { CookiesLanding } from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies.
+ */
+import AssembledCookiesLanding from '../cookieLanding';
+import { useCookie, useSettings } from '../../../stateProviders';
+import data from '../../../../../utils/test-data/cookieMockData';
+
+jest.mock('../../../stateProviders', () => ({
+ useCookie: jest.fn(),
+ useSettings: jest.fn(),
+}));
+const mockUseCookieStore = useCookie as jest.Mock;
+const mockUseSettingsStore = useSettings as jest.Mock;
+
+describe('CookiesLanding', () => {
+ beforeAll(() => {
+ globalThis.chrome = SinonChrome as unknown as typeof chrome;
+ globalThis.chrome = {
+ ...SinonChrome,
+ storage: {
+ //@ts-ignore
+ local: {
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ get: (_, __) =>
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ new Promise<{ [key: string]: any }>((resolve) => {
+ resolve({
+ 40245632: {
+ cookies: data.tabCookies,
+ selectedSidebarItem: 'privacySandbox#cookies',
+ tablePersistentSettingsStore: {
+ cookieListing: {
+ sortBy: 'parsedCookie.name',
+ sortOrder: 'asc',
+ },
+ },
+ },
+ tabToRead: '40245632',
+ });
+ }),
+ set: () => Promise.resolve(),
+ //@ts-ignore
+ onChanged: {
+ addListener: () => undefined,
+ removeListener: () => undefined,
+ },
+ },
+ sync: {
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ get: (_, __) =>
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ new Promise<{ [key: string]: any }>((resolve) => {
+ resolve({
+ allowedNumberOfTabs: 'single',
+ });
+ }),
+ set: () => Promise.resolve(),
+ //@ts-ignore
+ onChanged: {
+ addListener: () => undefined,
+ removeListener: () => undefined,
+ },
+ },
+ session: {
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ get: (_, __) => Promise.resolve(),
+ set: () => Promise.resolve(),
+ //@ts-ignore
+ onChanged: {
+ addListener: () => undefined,
+ removeListener: () => undefined,
+ },
+ },
+ },
+ devtools: {
+ //@ts-ignore
+ inspectedWindow: {
+ tabId: 40245632,
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
+ eval: (_, callback: any) => {
+ callback('https://edition.cnn.com');
+ },
+ //@ts-ignore
+ onResourceAdded: {
+ addListener: () => undefined,
+ removeListener: () => undefined,
+ },
+ },
+ },
+ tabs: {
+ //@ts-ignore
+ onUpdated: {
+ addListener: () => undefined,
+ removeListener: () => undefined,
+ },
+ //@ts-ignore
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ query: (_, __) => {
+ return [{ id: 40245632, url: 'https://edition.cnn.com' }];
+ },
+ connect: () => ({
+ //@ts-ignore
+ onMessage: {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ addListener: () => undefined,
+ },
+ //@ts-ignore
+ onDisconnect: {
+ addListener: () => undefined,
+ },
+ }),
+ },
+ };
+ });
+
+ it('renders CookiesLanding with data', () => {
+ mockUseCookieStore.mockReturnValue({
+ tabCookies: data.tabCookies,
+ tabFrames: data.tabFrames,
+ frameHasCookies: {
+ 'https://edition.cnn.com/': true,
+ },
+ });
+ mockUseSettingsStore.mockReturnValue({ isUsingCDP: false });
+ const { getByTestId, getAllByTestId } = render(
+
+
+
+ );
+
+ expect(getByTestId('cookies-landing')).toBeInTheDocument();
+ expect(getAllByTestId('cookies-landing-header')[0]).toBeInTheDocument();
+ expect(getByTestId('cookies-matrix-Categories')).toBeInTheDocument();
+ });
+});
diff --git a/packages/extension/src/view/devtools/components/facilitatedTesting/faciliatedTestingContent/infoCards.tsx b/packages/extension/src/view/devtools/components/facilitatedTesting/faciliatedTestingContent/infoCards.tsx
index 6225413b9..c0fa48ead 100644
--- a/packages/extension/src/view/devtools/components/facilitatedTesting/faciliatedTestingContent/infoCards.tsx
+++ b/packages/extension/src/view/devtools/components/facilitatedTesting/faciliatedTestingContent/infoCards.tsx
@@ -20,9 +20,11 @@
import React from 'react';
import { addUTMParams } from '@ps-analysis-tool/common';
+const EXPERIMENT_GROUP = 'Membership in Experiment Group';
+
const INFO_CARDS_DATA = [
{
- heading: 'Membership in Experiment Group',
+ heading: EXPERIMENT_GROUP,
content: `To prepare for third-party cookie deprecation, we will be providing Chrome-facilitated testing modes that allow sites to preview how site behavior and functionality work without third-party cookies. Check
+ {card.heading === EXPERIMENT_GROUP && (
+
+
+ For browsers in the 1% group, users will get a new
+ chrome://settings/trackingProtection page instead of
+ chrome://settings/cookies
+
+
+ )}
diff --git a/packages/extension/src/view/devtools/components/facilitatedTesting/index.tsx b/packages/extension/src/view/devtools/components/facilitatedTesting/index.tsx
index bf281a10c..157aee7b5 100644
--- a/packages/extension/src/view/devtools/components/facilitatedTesting/index.tsx
+++ b/packages/extension/src/view/devtools/components/facilitatedTesting/index.tsx
@@ -19,6 +19,10 @@
*/
import React from 'react';
import { LandingPage } from '@ps-analysis-tool/design-system';
+
+/**
+ * Internal dependencies.
+ */
import FacilitatedTestingContent from './faciliatedTestingContent';
const FacilitatedTesting = () => (
diff --git a/packages/extension/src/view/devtools/components/facilitatedTesting/tests/index.tsx b/packages/extension/src/view/devtools/components/facilitatedTesting/tests/index.tsx
new file mode 100644
index 000000000..9b70e2c8b
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/facilitatedTesting/tests/index.tsx
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import SinonChrome from 'sinon-chrome';
+/**
+ * Internal dependencies
+ */
+import FacilitatedTesting from '..';
+//@ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
+import { act } from 'react-dom/test-utils';
+
+describe('FacilitatedTesting Landing Pages', () => {
+ beforeAll(() => {
+ globalThis.chrome = SinonChrome as unknown as typeof chrome;
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...PSInfo,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('should render FacilitatedTesting', async () => {
+ act(() => {
+ render( );
+ });
+ expect(
+ await screen.findByTestId('facilitated-testing-content')
+ ).toBeInTheDocument();
+ });
+});
diff --git a/packages/extension/src/view/devtools/components/index.ts b/packages/extension/src/view/devtools/components/index.ts
index 88a630178..1d225e910 100644
--- a/packages/extension/src/view/devtools/components/index.ts
+++ b/packages/extension/src/view/devtools/components/index.ts
@@ -20,3 +20,4 @@ export { default as Cookies } from './cookies';
export { default as PrivacySandbox } from './privacySandbox';
export { default as Settings } from './settings';
export { default as FacilitatedTesting } from './facilitatedTesting';
+export { default as Layout } from './layout';
diff --git a/packages/extension/src/view/devtools/components/layout.tsx b/packages/extension/src/view/devtools/components/layout.tsx
new file mode 100644
index 000000000..d33693718
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/layout.tsx
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { type CookieTableData } from '@ps-analysis-tool/common';
+import {
+ Sidebar,
+ useSidebar,
+ type SidebarItems,
+ CookieIconWhite,
+ CookieIcon,
+ InspectButton,
+ ToastMessage,
+ SIDEBAR_ITEMS_KEYS,
+} from '@ps-analysis-tool/design-system';
+import { Resizable } from 're-resizable';
+
+/**
+ * Internal dependencies.
+ */
+import Cookies from './cookies';
+import useFrameOverlay from '../hooks/useFrameOverlay';
+import { useCookie, useSettings } from '../stateProviders';
+import { getCurrentTabId } from '../../../utils/getCurrentTabId';
+
+interface LayoutProps {
+ setSidebarData: React.Dispatch>;
+}
+
+const Layout = ({ setSidebarData }: LayoutProps) => {
+ const [sidebarWidth, setSidebarWidth] = useState(200);
+ const mainRef = useRef(null);
+
+ const { settingsChanged, handleSettingsChange } = useSettings(
+ ({ state, actions }) => ({
+ settingsChanged: state.settingsChanged,
+ handleSettingsChange: actions.handleSettingsChange,
+ })
+ );
+
+ const {
+ tabFrames,
+ frameHasCookies,
+ canStartInspecting,
+ tabUrl,
+ isInspecting,
+ setIsInspecting,
+ selectedFrame,
+ setSelectedFrame,
+ } = useCookie(({ state, actions }) => ({
+ tabFrames: state.tabFrames,
+ frameHasCookies: state.frameHasCookies,
+ canStartInspecting: state.canStartInspecting,
+ tabUrl: state.tabUrl,
+ isInspecting: state.isInspecting,
+ setIsInspecting: actions.setIsInspecting,
+ selectedFrame: state.selectedFrame,
+ setSelectedFrame: actions.setSelectedFrame,
+ }));
+
+ const {
+ activePanel,
+ selectedItemKey,
+ currentItemKey,
+ isSidebarFocused,
+ updateSelectedItemKey,
+ isKeySelected,
+ } = useSidebar(({ state, actions }) => ({
+ activePanel: state.activePanel,
+ selectedItemKey: state.selectedItemKey,
+ currentItemKey: state.currentItemKey,
+ isSidebarFocused: state.isSidebarFocused,
+ updateSelectedItemKey: actions.updateSelectedItemKey,
+ isKeySelected: actions.isKeySelected,
+ }));
+
+ const { Element: PanelElement, props } = activePanel.panel;
+
+ useEffect(() => {
+ setSidebarData((prev) => {
+ const data = { ...prev };
+ const psData = data[SIDEBAR_ITEMS_KEYS.PRIVACY_SANDBOX];
+
+ psData.children[SIDEBAR_ITEMS_KEYS.COOKIES].panel = {
+ Element: Cookies,
+ props: { setFilteredCookies },
+ };
+ psData.children[SIDEBAR_ITEMS_KEYS.COOKIES].children = Object.keys(
+ tabFrames || {}
+ ).reduce((acc, url) => {
+ const popupTitle = `Cookies used by frames from ${url}`;
+
+ acc[url] = {
+ title: url,
+ popupTitle,
+ panel: {
+ Element: Cookies,
+ props: { setFilteredCookies },
+ },
+ icon: {
+ Element: CookieIcon,
+ },
+ selectedIcon: {
+ Element: CookieIconWhite,
+ },
+ children: {},
+ isBlurred: !frameHasCookies?.[url],
+ };
+
+ return acc;
+ }, {});
+
+ const showInspectButton =
+ canStartInspecting && Boolean(Object.keys(tabFrames || {}).length);
+
+ if (showInspectButton) {
+ psData.children[SIDEBAR_ITEMS_KEYS.COOKIES].extraInterfaceToTitle = {
+ Element: InspectButton,
+ props: {
+ isInspecting,
+ setIsInspecting,
+ isTabFocused:
+ isSidebarFocused && isKeySelected(SIDEBAR_ITEMS_KEYS.COOKIES),
+ },
+ };
+ } else {
+ psData.children[SIDEBAR_ITEMS_KEYS.COOKIES].extraInterfaceToTitle = {};
+ }
+
+ return data;
+ });
+ }, [
+ canStartInspecting,
+ frameHasCookies,
+ isInspecting,
+ isKeySelected,
+ isSidebarFocused,
+ setIsInspecting,
+ setSidebarData,
+ tabFrames,
+ ]);
+
+ useEffect(() => {
+ if (Object.keys(tabFrames || {}).includes(currentItemKey || '')) {
+ setSelectedFrame(currentItemKey);
+ } else {
+ setSelectedFrame(null);
+ }
+ }, [currentItemKey, setSelectedFrame, tabFrames]);
+
+ useEffect(() => {
+ (async () => {
+ const tabId = await getCurrentTabId();
+
+ if (!tabId) {
+ return;
+ }
+
+ let data = await chrome.storage.session.get();
+
+ if (!data) {
+ data = {};
+ }
+
+ data['selectedSidebarItem#' + tabId] = selectedItemKey;
+
+ await chrome.storage.session.set(data);
+ })();
+ }, [selectedItemKey]);
+
+ const lastUrl = useRef(tabUrl);
+
+ useEffect(() => {
+ if (lastUrl.current === tabUrl || lastUrl.current === null) {
+ lastUrl.current = tabUrl;
+ return;
+ }
+
+ lastUrl.current = tabUrl;
+
+ updateSelectedItemKey(selectedFrame || SIDEBAR_ITEMS_KEYS.COOKIES);
+ }, [selectedFrame, setSelectedFrame, tabUrl, updateSelectedItemKey]);
+
+ const [filteredCookies, setFilteredCookies] = useState([]);
+
+ const handleUpdate = useCallback(
+ (key: string | null) => {
+ updateSelectedItemKey(key || SIDEBAR_ITEMS_KEYS.COOKIES);
+ },
+ [updateSelectedItemKey]
+ );
+
+ useFrameOverlay(filteredCookies, handleUpdate);
+
+ return (
+
+
{
+ setSidebarWidth((prevState) => prevState + d.width);
+ }}
+ minWidth={'150px'}
+ maxWidth={'90%'}
+ enable={{
+ right: true,
+ }}
+ className="h-full"
+ >
+
+
+
+
+
+ {settingsChanged && (
+
+ )}
+
+
+
+ );
+};
+
+export default Layout;
diff --git a/packages/extension/src/view/devtools/components/privateAdvertising/tests/index.tsx b/packages/extension/src/view/devtools/components/privateAdvertising/tests/index.tsx
new file mode 100644
index 000000000..ccf9d90b3
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/privateAdvertising/tests/index.tsx
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import SinonChrome from 'sinon-chrome';
+/**
+ * Internal dependencies
+ */
+import Attribution from '../attribution';
+import Topics from '../topics';
+//@ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
+import { act } from 'react-dom/test-utils';
+import PrivateAdvertising from '../privateAdvertising';
+
+describe('Private advertising Landing Pages', () => {
+ beforeAll(() => {
+ globalThis.chrome = SinonChrome as unknown as typeof chrome;
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...PSInfo,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('should render Attribution', async () => {
+ act(() => {
+ render( );
+ });
+
+ expect(
+ await screen.findByTestId('attribution-content')
+ ).toBeInTheDocument();
+ });
+
+ it('should render Private advertising', async () => {
+ act(() => {
+ render( );
+ });
+
+ expect(await screen.findByText('Private Advertising')).toBeInTheDocument();
+ });
+
+ it('should render Topics', async () => {
+ act(() => {
+ render( );
+ });
+
+ expect(await screen.findByTestId('topics-content')).toBeInTheDocument();
+ });
+});
diff --git a/packages/extension/src/view/devtools/components/settings/components/informationContainer.tsx b/packages/extension/src/view/devtools/components/settings/components/informationContainer.tsx
index fd628152c..ac9254ea1 100644
--- a/packages/extension/src/view/devtools/components/settings/components/informationContainer.tsx
+++ b/packages/extension/src/view/devtools/components/settings/components/informationContainer.tsx
@@ -22,7 +22,7 @@ import classNames from 'classnames';
/**
* Internal dependencies
*/
-import { useSettingsStore } from '../../../stateProviders/syncSettingsStore';
+import { useSettings } from '../../../stateProviders';
// @ts-ignore
// eslint-disable-next-line import/no-relative-packages
import InformationIcon from '../../../../../../../../assets/icons/information-icon.svg';
@@ -35,14 +35,14 @@ const InformationContainer = () => {
currentTabs,
currentExtensions,
browserInformation,
- PSATVersion,
OSInformation,
- } = useSettingsStore(({ state }) => ({
+ PSATVersion,
+ } = useSettings(({ state }) => ({
currentTabs: state.currentTabs,
currentExtensions: state.currentExtensions,
browserInformation: state.browserInformation,
- PSATVersion: state.PSATVersion,
OSInformation: state.OSInformation,
+ PSATVersion: state.PSATVersion,
}));
const [copying, setCopying] = useState(false);
@@ -136,9 +136,9 @@ const InformationContainer = () => {
)}
>
{copying ? (
diff --git a/packages/extension/src/view/devtools/components/settings/components/settingsContainer.tsx b/packages/extension/src/view/devtools/components/settings/components/settingsContainer.tsx
index e5dd6bf1d..d64377130 100644
--- a/packages/extension/src/view/devtools/components/settings/components/settingsContainer.tsx
+++ b/packages/extension/src/view/devtools/components/settings/components/settingsContainer.tsx
@@ -22,7 +22,7 @@ import React, { useMemo } from 'react';
* Internal dependencies
*/
import SettingOption from './settingOption';
-import { useSettingsStore } from '../../../stateProviders/syncSettingsStore';
+import { useSettings } from '../../../stateProviders';
// @ts-ignore
// eslint-disable-next-line import/no-relative-packages
import Gear from '../../../../../../../../assets/icons/gear.svg';
@@ -37,7 +37,7 @@ interface settingsToReturnObject {
}
const SettingsContainer = () => {
const { allowedNumberOfTabs, isUsingCDP, setIsUsingCDP, setProcessingMode } =
- useSettingsStore(({ state, actions }) => ({
+ useSettings(({ state, actions }) => ({
allowedNumberOfTabs: state.allowedNumberOfTabsForSettingsPageDisplay,
isUsingCDP: state.isUsingCDPForSettingsPageDisplay,
setProcessingMode: actions.setProcessingMode,
diff --git a/packages/extension/src/view/devtools/components/settings/components/tests/informationContainer.tsx b/packages/extension/src/view/devtools/components/settings/components/tests/informationContainer.tsx
index 46b22bae8..cca93e006 100644
--- a/packages/extension/src/view/devtools/components/settings/components/tests/informationContainer.tsx
+++ b/packages/extension/src/view/devtools/components/settings/components/tests/informationContainer.tsx
@@ -13,20 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/**
+ * External dependencies.
+ */
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
-import { useSettingsStore } from '../../../../stateProviders/syncSettingsStore';
-import InformationContainer from '../informationContainer';
import { act } from 'react-dom/test-utils';
+/**
+ * Internal dependencies
+ */
+import { useSettings } from '../../../../stateProviders/settings';
+import InformationContainer from '../informationContainer';
-jest.mock('../../../../stateProviders/syncSettingsStore', () => ({
- useSettingsStore: jest.fn(),
+jest.mock('../../../../stateProviders/settings', () => ({
+ useSettings: jest.fn(),
}));
-const mockUseSettingsStore = useSettingsStore as jest.Mock;
+const mockUseSettingsStore = useSettings as jest.Mock;
-describe('informationContainer', () => {
+describe('InformationContainer', () => {
it('should render the component', () => {
mockUseSettingsStore.mockReturnValue({
currentTabs: 0,
@@ -42,25 +48,47 @@ describe('informationContainer', () => {
expect(screen.getByTestId('debugging-information')).toBeInTheDocument();
});
+ it('Should show cookie table if frame is selected', () => {
+ mockUseSettingsStore.mockReturnValue({
+ currentTabs: 2,
+ currentExtensions: [
+ {
+ extensionName: 'Privacy Sandbox Analysis Tool',
+ extensionId: '1',
+ },
+ ],
+ browserInformation: '120.0.0.20',
+ OSInformation: 'MacOS (arm64)',
+ });
+
+ act(() => {
+ render( );
+ });
+
+ expect(
+ screen.getByText('Privacy Sandbox Analysis Tool: 1')
+ ).toBeInTheDocument();
+ expect(screen.getByText('MacOS (arm64)')).toBeInTheDocument();
+ expect(screen.getByText('120.0.0.20')).toBeInTheDocument();
+ });
+
it('should copy the text to clipboard', () => {
mockUseSettingsStore.mockReturnValue({
currentTabs: 2,
currentExtensions: [
{
- extensionName: 'test',
- extensionId: 'test',
+ extensionName: 'Privacy Sandbox Analysis Tool',
+ extensionId: '1',
},
],
- browserInformation: 'test browser',
+ browserInformation: '120.0.0.20',
+ OSInformation: 'MacOS (arm64)',
PSATVersion: '0.0.0',
- OSInformation: '0.1.0',
});
- render( );
-
- expect(mockUseSettingsStore).toHaveBeenCalled();
- expect(screen.getByTestId('debugging-information')).toBeInTheDocument();
- expect(screen.getByTestId('copy-button')).toBeInTheDocument();
+ act(() => {
+ render( );
+ });
global.document.execCommand = jest.fn(() => 'copy');
const events = {};
@@ -88,7 +116,7 @@ describe('informationContainer', () => {
expect(e.clipboardData.setData).toHaveBeenCalledWith(
'text/plain',
- '**Open Tabs:** 2\n**Active Extensions:**\ntest: test\n**Chrome Version:** test browser\n**PSAT Version:** 0.0.0\n**OS - System Architecture:** 0.1.0'
+ '**Open Tabs:** 2\n**Active Extensions:**\nPrivacy Sandbox Analysis Tool: 1\n**Chrome Version:** 120.0.0.20\n**PSAT Version:** 0.0.0\n**OS - System Architecture:** MacOS (arm64)'
);
expect(e.preventDefault).toHaveBeenCalled();
});
diff --git a/packages/extension/src/view/devtools/components/settings/components/tests/settingsContainer.tsx b/packages/extension/src/view/devtools/components/settings/components/tests/settingsContainer.tsx
new file mode 100644
index 000000000..0794c20f8
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/settings/components/tests/settingsContainer.tsx
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { act } from 'react-dom/test-utils';
+
+/**
+ * Internal dependencies.
+ */
+import SettingsContainer from '../settingsContainer';
+import { useSettings } from '../../../../stateProviders';
+import { noop } from '@ps-analysis-tool/common';
+
+jest.mock('../../../../stateProviders', () => ({
+ useSettings: jest.fn(),
+}));
+
+const mockUseSettingsStore = useSettings as jest.Mock;
+
+describe('SettingsContainer', () => {
+ it('Should enable multitab debugging', async () => {
+ mockUseSettingsStore.mockReturnValueOnce({
+ allowedNumberOfTabs: 'single',
+ isUsingCDP: false,
+ setIsUsingCDP: noop,
+ setProcessingMode: noop,
+ });
+
+ act(() => {
+ render( );
+ });
+
+ const toggleButtonInput = await screen.findAllByTestId(
+ 'toggle-button-input'
+ );
+
+ expect((await screen.findAllByTestId('toggle-button'))[1]).toHaveClass(
+ 'bg-quartz'
+ );
+
+ toggleButtonInput[1].click();
+
+ mockUseSettingsStore.mockReturnValueOnce({
+ allowedNumberOfTabs: 'unlimited',
+ isUsingCDP: false,
+ setIsUsingCDP: noop,
+ setProcessingMode: noop,
+ });
+
+ act(() => {
+ render( );
+ });
+
+ expect((await screen.findAllByTestId('toggle-button'))[3]).toHaveClass(
+ 'bg-toggle-on'
+ );
+ });
+
+ it('Should enable CDP', async () => {
+ mockUseSettingsStore.mockReturnValueOnce({
+ allowedNumberOfTabs: 'single',
+ isUsingCDP: false,
+ setIsUsingCDP: noop,
+ setProcessingMode: noop,
+ });
+
+ act(() => {
+ render( );
+ });
+
+ const toggleButtonInput = await screen.findAllByTestId(
+ 'toggle-button-input'
+ );
+
+ expect((await screen.findAllByTestId('toggle-button'))[0]).toHaveClass(
+ 'bg-quartz'
+ );
+
+ toggleButtonInput[0].click();
+
+ mockUseSettingsStore.mockReturnValueOnce({
+ allowedNumberOfTabs: 'single',
+ isUsingCDP: true,
+ setIsUsingCDP: noop,
+ setProcessingMode: noop,
+ });
+
+ act(() => {
+ render( );
+ });
+
+ expect((await screen.findAllByTestId('toggle-button'))[2]).toHaveClass(
+ 'bg-toggle-on'
+ );
+ });
+});
diff --git a/packages/extension/src/view/devtools/components/settings/index.tsx b/packages/extension/src/view/devtools/components/settings/index.tsx
index 477fa1d0e..6163cb471 100644
--- a/packages/extension/src/view/devtools/components/settings/index.tsx
+++ b/packages/extension/src/view/devtools/components/settings/index.tsx
@@ -42,6 +42,7 @@ const Settings = () => {
}`}
>
setOpen((prevOpen) => !prevOpen)}
>
@@ -53,7 +54,10 @@ const Settings = () => {
-
+
diff --git a/packages/extension/src/view/devtools/components/settings/tests/index.tsx b/packages/extension/src/view/devtools/components/settings/tests/index.tsx
new file mode 100644
index 000000000..dd83d73f9
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/settings/tests/index.tsx
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { act } from 'react-dom/test-utils';
+import '@testing-library/jest-dom';
+import SinonChrome from 'sinon-chrome';
+import { noop } from '@ps-analysis-tool/common';
+/**
+ * Internal dependencies
+ */
+import { useSettings } from '../../../stateProviders';
+import Settings from '..';
+//@ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
+
+jest.mock('../../../stateProviders', () => ({
+ useSettings: jest.fn(),
+}));
+
+const mockUseSettingsStore = useSettings as jest.Mock;
+
+describe('Settings Page', () => {
+ beforeAll(() => {
+ globalThis.chrome = SinonChrome as unknown as typeof chrome;
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...PSInfo,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('Should render settings page', () => {
+ mockUseSettingsStore.mockReturnValue({
+ allowedNumberOfTabs: 'single',
+ isUsingCDP: false,
+ setIsUsingCDP: noop,
+ setProcessingMode: noop,
+ currentTabs: 2,
+ currentExtensions: [
+ {
+ extensionName: 'Privacy Sandbox Analysis Tool',
+ extensionId: '1',
+ },
+ ],
+ browserInformation: '120.0.0.20',
+ OSInformation: 'MacOS (arm64)',
+ });
+
+ act(() => {
+ render(
);
+ });
+
+ expect(screen.getByTestId('settings-main-content')).not.toHaveClass(
+ 'hidden'
+ );
+ act(() => {
+ screen.getByTestId('settings-collapse-button').click();
+ });
+
+ expect(screen.getByTestId('settings-main-content')).toHaveClass('hidden');
+ });
+});
diff --git a/packages/design-system/src/components/cookiesLanding/tests/cookiesLanding.tsx b/packages/extension/src/view/devtools/components/siteBoundaries/relatedWebsiteSets/insights/tests/siteList.tsx
similarity index 50%
rename from packages/design-system/src/components/cookiesLanding/tests/cookiesLanding.tsx
rename to packages/extension/src/view/devtools/components/siteBoundaries/relatedWebsiteSets/insights/tests/siteList.tsx
index 14617e4b2..cc16f9188 100644
--- a/packages/design-system/src/components/cookiesLanding/tests/cookiesLanding.tsx
+++ b/packages/extension/src/view/devtools/components/siteBoundaries/relatedWebsiteSets/insights/tests/siteList.tsx
@@ -13,32 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/**
* External dependencies.
*/
import React from 'react';
-import { render } from '@testing-library/react';
-import '@testing-library/jest-dom/extend-expect';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
/**
* Internal dependencies.
*/
-import mockResponse from '../../../test-data/cookieMockData';
-import CookiesLanding from '..';
+import SitesList from '../sitesList';
+
+describe('RelatedWebsiteSets Insights SitesList', () => {
+ test('should render nothing', () => {
+ const { container } = render(
+
+ );
+
+ expect(container).toBeEmptyDOMElement();
+ });
-describe('CookiesLanding', () => {
- it('renders CookiesLanding with data', () => {
- const { getByTestId, getAllByTestId } = render(
-
+ test('should render sites', () => {
+ render(
+
);
- expect(getByTestId('cookies-landing')).toBeInTheDocument();
- expect(getAllByTestId('cookies-landing-header')[0]).toBeInTheDocument();
- expect(getByTestId('cookies-matrix-Categories')).toBeInTheDocument();
+ expect(screen.getByText('Associated sites')).toBeInTheDocument();
+ expect(screen.getByText('https://livemint.com')).toBeInTheDocument();
});
});
diff --git a/packages/extension/src/view/devtools/components/siteBoundaries/tests/index.tsx b/packages/extension/src/view/devtools/components/siteBoundaries/tests/index.tsx
new file mode 100644
index 000000000..0c36a1e5a
--- /dev/null
+++ b/packages/extension/src/view/devtools/components/siteBoundaries/tests/index.tsx
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import SinonChrome from 'sinon-chrome';
+/**
+ * Internal dependencies
+ */
+import Chips from '../chips';
+import RelatedWebsiteSets from '../relatedWebsiteSets';
+//@ts-ignore
+// eslint-disable-next-line import/no-unresolved
+import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
+import { act } from 'react-dom/test-utils';
+
+describe('Private advertising Landing Pages', () => {
+ beforeAll(() => {
+ globalThis.chrome = SinonChrome as unknown as typeof chrome;
+ globalThis.fetch = function () {
+ return Promise.resolve({
+ json: () =>
+ Promise.resolve({
+ ...PSInfo,
+ }),
+ text: () => Promise.resolve({}),
+ });
+ } as unknown as typeof fetch;
+ });
+
+ it('should render RelatedWebsiteSets', async () => {
+ act(() => {
+ render(
);
+ });
+
+ expect(
+ await screen.findByTestId('related-website-sets-content')
+ ).toBeInTheDocument();
+ });
+
+ it('should render Chips', async () => {
+ act(() => {
+ render(
);
+ });
+
+ expect(await screen.findByTestId('chips-content')).toBeInTheDocument();
+ });
+});
diff --git a/packages/extension/src/view/devtools/hooks/useContextInvalidated.ts b/packages/extension/src/view/devtools/hooks/useContextInvalidated.ts
new file mode 100644
index 000000000..e1b75f216
--- /dev/null
+++ b/packages/extension/src/view/devtools/hooks/useContextInvalidated.ts
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { useCallback, useEffect, type MutableRefObject } from 'react';
+
+/**
+ * Internal dependencies.
+ */
+import { useCookie, useSettings } from '../stateProviders';
+import { getCurrentTabId } from '../../../utils/getCurrentTabId';
+
+const useContextInvalidated = (
+ contextInvalidatedRef: MutableRefObject
+): boolean => {
+ const { contextInvalidated, setContextInvalidated } = useCookie(
+ ({ state, actions }) => ({
+ contextInvalidated: state.contextInvalidated,
+ setContextInvalidated: actions.setContextInvalidated,
+ })
+ );
+
+ const { allowedNumberOfTabs, isUsingCDP } = useSettings(({ state }) => ({
+ allowedNumberOfTabs: state.allowedNumberOfTabs,
+ isUsingCDP: state.isUsingCDP,
+ }));
+
+ const listenToMouseChange = useCallback(() => {
+ if (contextInvalidatedRef.current) {
+ if (!chrome.runtime?.id) {
+ setContextInvalidated(true);
+ localStorage.setItem('contextInvalidated', 'true');
+ }
+ }
+ }, [setContextInvalidated, contextInvalidatedRef]);
+
+ useEffect(() => {
+ window.addEventListener('mouseover', listenToMouseChange);
+
+ return () => {
+ window.removeEventListener('mouseover', listenToMouseChange);
+ };
+ }, [listenToMouseChange]);
+
+ useEffect(() => {
+ (async () => {
+ const localStorageFlag = localStorage.getItem('contextInvalidated');
+
+ if (
+ localStorageFlag &&
+ localStorageFlag === 'true' &&
+ allowedNumberOfTabs === 'unlimited'
+ ) {
+ const tabId = await getCurrentTabId();
+
+ if (tabId) {
+ chrome.tabs.reload(Number(tabId));
+ if (isUsingCDP) {
+ try {
+ await chrome.debugger.attach(
+ { tabId: chrome.devtools.inspectedWindow.tabId },
+ '1.3'
+ );
+ await chrome.debugger.sendCommand(
+ { tabId: chrome.devtools.inspectedWindow.tabId },
+ 'Network.enable'
+ );
+ await chrome.debugger.sendCommand(
+ { tabId: chrome.devtools.inspectedWindow.tabId },
+ 'Audits.enable'
+ );
+ } catch (error) {
+ //Fail silently
+ }
+ }
+ }
+ localStorage.removeItem('contextInvalidated');
+ }
+ })();
+ }, [allowedNumberOfTabs, isUsingCDP]);
+
+ return contextInvalidated;
+};
+
+export default useContextInvalidated;
diff --git a/packages/extension/src/view/devtools/hooks/useFrameOverlay.ts b/packages/extension/src/view/devtools/hooks/useFrameOverlay.ts
index 667c5549f..e8d724487 100644
--- a/packages/extension/src/view/devtools/hooks/useFrameOverlay.ts
+++ b/packages/extension/src/view/devtools/hooks/useFrameOverlay.ts
@@ -23,8 +23,7 @@ import type { CookieTableData } from '@ps-analysis-tool/common';
* Internal dependencies.
*/
import { WEBPAGE_PORT_NAME } from '../../../constants';
-import { useCookieStore } from '../stateProviders/syncCookieStore';
-import { useSettingsStore } from '../stateProviders/syncSettingsStore';
+import { useCookie, useSettings } from '../stateProviders';
import { getCurrentTabId } from '../../../utils/getCurrentTabId';
interface Response {
@@ -46,7 +45,7 @@ const useFrameOverlay = (
tabFrames,
setCanStartInspecting,
canStartInspecting,
- } = useCookieStore(({ state, actions }) => ({
+ } = useCookie(({ state, actions }) => ({
setContextInvalidated: actions.setContextInvalidated,
isInspecting: state.isInspecting,
setIsInspecting: actions.setIsInspecting,
@@ -57,7 +56,7 @@ const useFrameOverlay = (
canStartInspecting: state.canStartInspecting,
}));
- const { allowedNumberOfTabs } = useSettingsStore(({ state }) => ({
+ const { allowedNumberOfTabs } = useSettings(({ state }) => ({
allowedNumberOfTabs: state.allowedNumberOfTabs,
}));
diff --git a/packages/extension/src/view/devtools/index.tsx b/packages/extension/src/view/devtools/index.tsx
index 6998698c5..a880df08d 100644
--- a/packages/extension/src/view/devtools/index.tsx
+++ b/packages/extension/src/view/devtools/index.tsx
@@ -29,9 +29,11 @@ import { LibraryDetectionProvider } from '@ps-analysis-tool/library-detection';
* Internal dependencies.
*/
import App from './app';
-import { Provider as ExternalStoreProvider } from './stateProviders/syncCookieStore';
-import { Provider as SettingsStoreProvider } from './stateProviders/syncSettingsStore';
-import { Provider as AllowedListProvider } from './stateProviders/useAllowedList';
+import {
+ CookieProvider,
+ SettingsProvider,
+ AllowedListProvider,
+} from './stateProviders';
const isDarkMode = chrome.devtools.panels.themeName === 'dark';
document.body.classList.add(isDarkMode ? 'dark' : 'light');
@@ -41,8 +43,8 @@ const root = document.getElementById('root');
if (root) {
createRoot(root).render(
-
-
+
+
@@ -50,8 +52,8 @@ if (root) {
-
-
+
+
);
}
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/index.tsx b/packages/extension/src/view/devtools/stateProviders/allowedList/allowedListProvider.tsx
similarity index 70%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/index.tsx
rename to packages/extension/src/view/devtools/stateProviders/allowedList/allowedListProvider.tsx
index 322d39760..5b6ca1241 100644
--- a/packages/extension/src/view/devtools/stateProviders/useAllowedList/index.tsx
+++ b/packages/extension/src/view/devtools/stateProviders/allowedList/allowedListProvider.tsx
@@ -23,42 +23,18 @@ import React, {
useState,
type PropsWithChildren,
} from 'react';
-import { noop } from '@ps-analysis-tool/common';
-import { createContext } from 'use-context-selector';
/**
* Internal dependencies.
*/
import { getCurrentTab } from '../../../../utils/getCurrentTabId';
-import { useCookieStore } from '../syncCookieStore';
+import { useCookie } from '../cookie';
import setDomainsInAllowList from './utils/setDomainsInAllowList';
import getDotPrefixedDomain from './utils/getDotPrefixedDomain';
-import useContextSelector from '../../../../utils/useContextSelector';
-
-export interface AllowedListContext {
- state: {
- domainsInAllowList: Set;
- isIncognito: boolean;
- };
- actions: {
- setDomainsInAllowListCallback: (list: Set) => void;
- };
-}
-
-const initialState: AllowedListContext = {
- state: {
- domainsInAllowList: new Set(),
- isIncognito: false,
- },
- actions: {
- setDomainsInAllowListCallback: noop,
- },
-};
-
-export const Context = createContext(initialState);
+import Context from './context';
-export const Provider = ({ children }: PropsWithChildren) => {
- const { tabUrl, cookies } = useCookieStore(({ state }) => ({
+const Provider = ({ children }: PropsWithChildren) => {
+ const { tabUrl, cookies } = useCookie(({ state }) => ({
tabUrl: state.tabUrl,
cookies: state.tabCookies,
}));
@@ -143,19 +119,4 @@ export const Provider = ({ children }: PropsWithChildren) => {
);
};
-export function useAllowedList(): AllowedListContext;
-export function useAllowedList(
- selector: (state: AllowedListContext) => T
-): T;
-
-/**
- * Allowed list hook.
- * @param selector Selector function to partially select state.
- * @returns selected part of the state
- */
-export function useAllowedList(
- selector: (state: AllowedListContext) => T | AllowedListContext = (state) =>
- state
-) {
- return useContextSelector(Context, selector);
-}
+export default Provider;
diff --git a/packages/extension/src/view/devtools/stateProviders/allowedList/context.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/context.ts
new file mode 100644
index 000000000..08a305a3a
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/allowedList/context.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import { noop, createContext } from '@ps-analysis-tool/common';
+
+export interface AllowedListStoreContext {
+ state: {
+ domainsInAllowList: Set;
+ isIncognito: boolean;
+ };
+ actions: {
+ setDomainsInAllowListCallback: (list: Set) => void;
+ };
+}
+
+const initialState: AllowedListStoreContext = {
+ state: {
+ domainsInAllowList: new Set(),
+ isIncognito: false,
+ },
+ actions: {
+ setDomainsInAllowListCallback: noop,
+ },
+};
+
+export default createContext(initialState);
diff --git a/packages/extension/src/view/devtools/stateProviders/allowedList/index.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/index.ts
new file mode 100644
index 000000000..030f42d3b
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/allowedList/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as AllowedListProvider } from './allowedListProvider';
+export {
+ default as AllowedListContext,
+ type AllowedListStoreContext,
+} from './context';
+export { default as useAllowedList } from './useAllowedList';
diff --git a/packages/extension/src/view/devtools/stateProviders/allowedList/useAllowedList.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/useAllowedList.ts
new file mode 100644
index 000000000..6e801a492
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/allowedList/useAllowedList.ts
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import { useContextSelector } from '@ps-analysis-tool/common';
+/**
+ * Internal dependencies.
+ */
+import Context, { type AllowedListStoreContext } from './context';
+
+export function useAllowedList(): AllowedListStoreContext;
+export function useAllowedList(
+ selector: (state: AllowedListStoreContext) => T
+): T;
+
+/**
+ * Allowed list hook.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useAllowedList(
+ selector: (state: AllowedListStoreContext) => T | AllowedListStoreContext = (
+ state
+ ) => state
+) {
+ return useContextSelector(Context, selector);
+}
+
+export default useAllowedList;
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/getDotPrefixedDomain.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/getDotPrefixedDomain.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/getDotPrefixedDomain.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/getDotPrefixedDomain.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/index.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/index.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/index.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/index.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/isCookieDomainInAllowList.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/isCookieDomainInAllowList.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/isCookieDomainInAllowList.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/isCookieDomainInAllowList.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/onAllowListClick.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/onAllowListClick.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/onAllowListClick.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/onAllowListClick.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/removeFromAllowList.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/removeFromAllowList.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/removeFromAllowList.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/removeFromAllowList.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/setDomainsInAllowList.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/setDomainsInAllowList.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/setDomainsInAllowList.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/setDomainsInAllowList.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/setParentDomain.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/setParentDomain.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/setParentDomain.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/setParentDomain.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/tests/onAllowListClick.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/tests/onAllowListClick.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/tests/onAllowListClick.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/tests/onAllowListClick.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/tests/setDomainsInAllowList.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/tests/setDomainsInAllowList.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/tests/setDomainsInAllowList.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/tests/setDomainsInAllowList.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/tests/setParentDomain.ts b/packages/extension/src/view/devtools/stateProviders/allowedList/utils/tests/setParentDomain.ts
similarity index 100%
rename from packages/extension/src/view/devtools/stateProviders/useAllowedList/utils/tests/setParentDomain.ts
rename to packages/extension/src/view/devtools/stateProviders/allowedList/utils/tests/setParentDomain.ts
diff --git a/packages/extension/src/view/devtools/stateProviders/cookie/context.ts b/packages/extension/src/view/devtools/stateProviders/cookie/context.ts
new file mode 100644
index 000000000..c2fedb938
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/cookie/context.ts
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import {
+ noop,
+ createContext,
+ type TabCookies,
+ type TabFrames,
+} from '@ps-analysis-tool/common';
+
+export interface CookieStoreContext {
+ state: {
+ tabCookies: TabCookies | null;
+ tabUrl: string | null;
+ loading: boolean;
+ tabFrames: TabFrames | null;
+ selectedFrame: string | null;
+ returningToSingleTab: boolean;
+ isCurrentTabBeingListenedTo: boolean;
+ isInspecting: boolean;
+ contextInvalidated: boolean;
+ canStartInspecting: boolean;
+ tabToRead: string | null;
+ frameHasCookies: Record;
+ };
+ actions: {
+ setSelectedFrame: (key: string | null) => void;
+ setIsInspecting: React.Dispatch>;
+ changeListeningToThisTab: () => void;
+ getCookiesSetByJavascript: () => void;
+ setContextInvalidated: React.Dispatch>;
+ setCanStartInspecting: React.Dispatch>;
+ };
+}
+
+const initialState: CookieStoreContext = {
+ state: {
+ tabCookies: null,
+ tabUrl: null,
+ tabFrames: null,
+ selectedFrame: null,
+ loading: true,
+ isCurrentTabBeingListenedTo: false,
+ returningToSingleTab: false,
+ isInspecting: false,
+ contextInvalidated: false,
+ canStartInspecting: false,
+ tabToRead: null,
+ frameHasCookies: {},
+ },
+ actions: {
+ setSelectedFrame: noop,
+ changeListeningToThisTab: noop,
+ setIsInspecting: noop,
+ getCookiesSetByJavascript: noop,
+ setContextInvalidated: noop,
+ setCanStartInspecting: noop,
+ },
+};
+
+export default createContext(initialState);
diff --git a/packages/extension/src/view/devtools/stateProviders/syncCookieStore/index.tsx b/packages/extension/src/view/devtools/stateProviders/cookie/cookieProvider.tsx
similarity index 60%
rename from packages/extension/src/view/devtools/stateProviders/syncCookieStore/index.tsx
rename to packages/extension/src/view/devtools/stateProviders/cookie/cookieProvider.tsx
index ffb142534..e790654b2 100644
--- a/packages/extension/src/view/devtools/stateProviders/syncCookieStore/index.tsx
+++ b/packages/extension/src/view/devtools/stateProviders/cookie/cookieProvider.tsx
@@ -16,7 +16,6 @@
/**
* External dependencies.
*/
-import { createContext } from 'use-context-selector';
import React, {
type PropsWithChildren,
useEffect,
@@ -25,72 +24,27 @@ import React, {
useRef,
useMemo,
} from 'react';
-import { noop } from '@ps-analysis-tool/design-system';
-import { type TabCookies, type TabFrames } from '@ps-analysis-tool/common';
+import { type TabCookies } from '@ps-analysis-tool/common';
/**
* Internal dependencies.
*/
-import useContextSelector from '../../../../utils/useContextSelector';
-import { ALLOWED_NUMBER_OF_TABS } from '../../../../constants';
-import isOnRWS from '../../../../contentScript/utils/isOnRWS';
-import { useSettingsStore } from '../syncSettingsStore';
-
-export interface CookieStoreContext {
- state: {
- tabCookies: TabCookies | null;
- tabUrl: string | null;
- loading: boolean;
- tabFrames: TabFrames | null;
- selectedFrame: string | null;
- returningToSingleTab: boolean;
- isCurrentTabBeingListenedTo: boolean;
- isInspecting: boolean;
- contextInvalidated: boolean;
- canStartInspecting: boolean;
- tabToRead: string | null;
- frameHasCookies: Record;
- };
- actions: {
- setSelectedFrame: (key: string | null) => void;
- setIsInspecting: React.Dispatch>;
- changeListeningToThisTab: () => void;
- getCookiesSetByJavascript: () => void;
- setContextInvalidated: React.Dispatch>;
- setCanStartInspecting: React.Dispatch>;
- };
-}
-
-const initialState: CookieStoreContext = {
- state: {
- tabCookies: null,
- tabUrl: null,
- tabFrames: null,
- selectedFrame: null,
- loading: true,
- isCurrentTabBeingListenedTo: false,
- returningToSingleTab: false,
- isInspecting: false,
- contextInvalidated: false,
- canStartInspecting: false,
- tabToRead: null,
- frameHasCookies: {},
- },
- actions: {
- setSelectedFrame: noop,
- changeListeningToThisTab: noop,
- setIsInspecting: noop,
- getCookiesSetByJavascript: noop,
- setContextInvalidated: noop,
- setCanStartInspecting: noop,
- },
-};
-
-export const Context = createContext(initialState);
-
-export const Provider = ({ children }: PropsWithChildren) => {
- // TODO: Refactor: create smaller providers and reduce state from here.
- const [tabId, setTabId] = useState(null);
+import {
+ ALLOWED_NUMBER_OF_TABS,
+ DEVTOOLS_CLOSE,
+ DEVTOOLS_OPEN,
+ GET_JS_COOKIES,
+ INITIAL_SYNC,
+ NEW_COOKIE_DATA,
+ SERVICE_WORKER_RELOAD_MESSAGE,
+ SET_TAB_TO_READ,
+} from '../../../../constants';
+import { useSettings } from '../settings';
+import { getTab } from '../../../../utils/getTab';
+import getFramesForCurrentTab from '../../../../utils/getFramesForCurrentTab';
+import Context, { type CookieStoreContext } from './context';
+
+const Provider = ({ children }: PropsWithChildren) => {
const [loading, setLoading] = useState(true);
const loadingTimeout = useRef | null>(null);
const [tabToRead, setTabToRead] = useState(null);
@@ -118,7 +72,7 @@ export const Provider = ({ children }: PropsWithChildren) => {
// This was converted to useRef because setting state was creating a race condition in rerendering the provider.
const isCurrentTabBeingListenedToRef = useRef(false);
- const { allowedNumberOfTabs, setSettingsChanged } = useSettingsStore(
+ const { allowedNumberOfTabs, setSettingsChanged } = useSettings(
({ state, actions }) => ({
allowedNumberOfTabs: state.allowedNumberOfTabs,
setSettingsChanged: actions.setSettingsChanged,
@@ -127,48 +81,11 @@ export const Provider = ({ children }: PropsWithChildren) => {
/**
* Set tab frames state for frame ids and frame URLs from using chrome.webNavigation.getAllFrames
- *
- * TODO: Refactor: move it to a utility function.
*/
- const getAllFramesForCurrentTab = useCallback(
- async (_tabId: number | null) => {
- if (!_tabId) {
- return;
- }
-
- const regexForFrameUrl =
- /^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:/\n?]+)/;
-
- const currentTabFrames = await chrome.webNavigation.getAllFrames({
- tabId: _tabId,
- });
- const modifiedTabFrames: TabFrames = {};
-
- currentTabFrames?.forEach(({ url, frameId, frameType }) => {
- if (url && url.includes('http')) {
- const parsedUrl = regexForFrameUrl.exec(url);
- if (parsedUrl && parsedUrl[0]) {
- if (modifiedTabFrames[parsedUrl[0]]) {
- modifiedTabFrames[parsedUrl[0]].frameIds.push(frameId);
- } else {
- modifiedTabFrames[parsedUrl[0]] = {
- frameIds: [frameId],
- frameType,
- };
- }
- }
- }
- });
- await Promise.all(
- Object.keys(modifiedTabFrames).map(async (tabFrame) => {
- modifiedTabFrames[tabFrame].isOnRWS = await isOnRWS(tabFrame);
- return tabFrame;
- })
- );
- setTabFrames(modifiedTabFrames);
- },
- []
- );
+ const getAllFramesForCurrentTab = useCallback(async () => {
+ const _tabFrames = await getFramesForCurrentTab();
+ setTabFrames(_tabFrames);
+ }, []);
/**
* Stores object with frame URLs as keys and boolean values indicating if the frame contains cookies.
@@ -230,31 +147,35 @@ export const Provider = ({ children }: PropsWithChildren) => {
* parses data currently in store, set current tab URL.
*/
const intitialSync = useCallback(async () => {
- const _tabId = chrome.devtools.inspectedWindow.tabId;
-
- setTabId(_tabId);
+ const tabId = chrome.devtools.inspectedWindow.tabId;
if (isCurrentTabBeingListenedToRef.current) {
- await getAllFramesForCurrentTab(_tabId);
+ await getAllFramesForCurrentTab();
}
+ const tab = await getTab(tabId);
+
if (chrome.devtools.inspectedWindow.tabId && canStartInspecting) {
await chrome.tabs.sendMessage(chrome.devtools.inspectedWindow.tabId, {
payload: {
- type: 'DEVTOOL::WEBPAGE::GET_JS_COOKIES',
+ type: GET_JS_COOKIES,
tabId: chrome.devtools.inspectedWindow.tabId,
},
});
}
- chrome.devtools.inspectedWindow.eval(
- 'window.location.href',
- (result, isException) => {
- if (!isException && typeof result === 'string') {
- setTabUrl(result);
+ if (tab?.url) {
+ setTabUrl(tab?.url);
+ } else {
+ chrome.devtools.inspectedWindow.eval(
+ 'window.location.href',
+ (result, isException) => {
+ if (!isException && typeof result === 'string') {
+ setTabUrl(result);
+ }
}
- }
- );
+ );
+ }
setLoading(false);
}, [getAllFramesForCurrentTab, canStartInspecting]);
@@ -263,7 +184,7 @@ export const Provider = ({ children }: PropsWithChildren) => {
if (chrome.devtools.inspectedWindow.tabId) {
await chrome.tabs.sendMessage(chrome.devtools.inspectedWindow.tabId, {
payload: {
- type: 'DEVTOOL::WEBPAGE::GET_JS_COOKIES',
+ type: GET_JS_COOKIES,
tabId: chrome.devtools.inspectedWindow.tabId,
},
});
@@ -271,17 +192,18 @@ export const Provider = ({ children }: PropsWithChildren) => {
}, []);
const changeListeningToThisTab = useCallback(() => {
+ const tabId = chrome.devtools.inspectedWindow.tabId;
if (!tabId) {
return;
}
chrome.runtime.sendMessage({
- type: 'DevTools::ServiceWorker::SET_TAB_TO_READ',
+ type: SET_TAB_TO_READ,
payload: {
tabId,
},
});
setTabToRead(tabId.toString());
- }, [tabId]);
+ }, []);
useEffect(() => {
if (
@@ -294,55 +216,66 @@ export const Provider = ({ children }: PropsWithChildren) => {
}
}, [allowedNumberOfTabs, tabFrames]);
- useEffect(() => {
- const listener = async (message: {
+ const messagePassingListener = useCallback(
+ async (message: {
type: string;
payload: {
tabId?: number;
cookieData?: TabCookies;
tabToRead?: string;
tabMode?: string;
+ psatOpenedAfterPageLoad?: boolean;
};
}) => {
- if (message.type === 'ServiceWorker::SET_TAB_TO_READ') {
- chrome.devtools.inspectedWindow.eval(
- 'window.location.href',
- (result, isException) => {
- if (!isException && typeof result === 'string') {
- setTabUrl(result);
- }
- }
- );
+ if (!message.type) {
+ return;
+ }
+ const tabId = chrome.devtools.inspectedWindow.tabId;
+ const incomingMessageType = message.type;
+
+ if (SET_TAB_TO_READ === incomingMessageType) {
+ const tab = await getTab(tabId?.toString() || '');
+ setTabUrl(tab?.url ?? '');
isCurrentTabBeingListenedToRef.current =
- tabId?.toString() === message?.payload?.tabId;
+ tabId === message?.payload?.tabId;
setTabToRead(message?.payload?.tabId?.toString() || null);
setTabFrames(null);
setLoading(false);
setCanStartInspecting(false);
}
- if (message.type === 'ServiceWorker::DevTools::INITIAL_SYNC') {
- if (message?.payload?.tabMode === 'unlimited') {
+ if (INITIAL_SYNC === incomingMessageType && message?.payload?.tabMode) {
+ if (message.payload.tabMode === 'unlimited') {
isCurrentTabBeingListenedToRef.current = true;
+ if (
+ Object.keys(message.payload).includes('psatOpenedAfterPageLoad') &&
+ message.payload.psatOpenedAfterPageLoad
+ ) {
+ setContextInvalidated(true);
+ localStorage.setItem('psatOpenedAfterPageLoad', 'true');
+ }
setTabToRead(null);
} else {
- if (tabId?.toString() !== message?.payload?.tabToRead) {
+ if (tabId.toString() !== message?.payload?.tabToRead) {
setTabFrames(null);
}
+
isCurrentTabBeingListenedToRef.current =
- tabId?.toString() === message?.payload?.tabToRead;
+ tabId.toString() === message?.payload?.tabToRead;
setTabToRead(message?.payload?.tabToRead || null);
}
}
- if (message.type === 'ServiceWorker::DevTools::NEW_COOKIE_DATA') {
- const data = message?.payload?.cookieData ?? {};
- if (
- message?.payload?.tabId &&
- tabId?.toString() === message?.payload?.tabId.toString()
- ) {
+ if (
+ NEW_COOKIE_DATA === incomingMessageType &&
+ message?.payload?.tabId &&
+ message?.payload?.cookieData
+ ) {
+ const data = message.payload.cookieData;
+
+ if (tabId.toString() === message.payload.tabId.toString()) {
if (isCurrentTabBeingListenedToRef.current) {
- await getAllFramesForCurrentTab(tabId);
+ await getAllFramesForCurrentTab();
setTabToRead(tabId.toString());
setTabCookies(Object.keys(data).length > 0 ? data : null);
} else {
@@ -351,20 +284,24 @@ export const Provider = ({ children }: PropsWithChildren) => {
}
}
- if (message.type === 'ServiceWorker::DevTools::TABS_RELOADED') {
+ if (message.type === SERVICE_WORKER_RELOAD_MESSAGE) {
setSettingsChanged(false);
}
- };
+ },
+ [getAllFramesForCurrentTab, setSettingsChanged]
+ );
- chrome.runtime.onMessage.addListener(listener);
+ useEffect(() => {
+ chrome.runtime.onMessage.addListener(messagePassingListener);
return () => {
- chrome.runtime.onMessage.removeListener(listener);
+ chrome.runtime.onMessage.removeListener(messagePassingListener);
};
- }, [getAllFramesForCurrentTab, tabId, setSettingsChanged]);
+ }, [messagePassingListener]);
const tabUpdateListener = useCallback(
async (_tabId: number, changeInfo: chrome.tabs.TabChangeInfo) => {
+ const tabId = chrome.devtools.inspectedWindow.tabId;
if (tabId === _tabId && changeInfo.url) {
setIsInspecting(false);
try {
@@ -384,11 +321,11 @@ export const Provider = ({ children }: PropsWithChildren) => {
setSelectedFrame(null);
} finally {
setTabFrames(null);
- await getAllFramesForCurrentTab(_tabId);
+ await getAllFramesForCurrentTab();
}
}
},
- [tabId, tabUrl, getAllFramesForCurrentTab, selectedFrame]
+ [tabUrl, getAllFramesForCurrentTab, selectedFrame]
);
const tabRemovedListener = useCallback(async () => {
@@ -435,22 +372,26 @@ export const Provider = ({ children }: PropsWithChildren) => {
}, []);
useEffect(() => {
+ const doNotReReload =
+ localStorage.getItem('contextInvalidated') &&
+ !localStorage.getItem('psatOpenedAfterPageLoad');
chrome.runtime.sendMessage({
- type: 'DevTools::ServiceWorker::DEVTOOLS_STATE_OPEN',
+ type: DEVTOOLS_OPEN,
payload: {
- tabId: tabId,
+ tabId: chrome.devtools.inspectedWindow.tabId,
+ doNotReReload,
},
});
return () => {
chrome.runtime.sendMessage({
- type: 'DevTools::ServiceWorker::DEVTOOLS_STATE_CLOSE',
+ type: DEVTOOLS_CLOSE,
payload: {
- tabId: tabId,
+ tabId: chrome.devtools.inspectedWindow.tabId,
},
});
};
- }, [tabId]);
+ }, []);
return (
{
);
};
-export function useCookieStore(): CookieStoreContext;
-export function useCookieStore(
- selector: (state: CookieStoreContext) => T
-): T;
-
-/**
- * Cookie store hook.
- * @param selector Selector function to partially select state.
- * @returns selected part of the state
- */
-export function useCookieStore(
- selector: (state: CookieStoreContext) => T | CookieStoreContext = (state) =>
- state
-) {
- return useContextSelector(Context, selector);
-}
+export default Provider;
diff --git a/packages/extension/src/view/devtools/stateProviders/cookie/index.ts b/packages/extension/src/view/devtools/stateProviders/cookie/index.ts
new file mode 100644
index 000000000..f0b1417a0
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/cookie/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as CookieProvider } from './cookieProvider';
+export { default as CookieContext, type CookieStoreContext } from './context';
+export { default as useCookie } from './useCookie';
diff --git a/packages/extension/src/view/devtools/stateProviders/cookie/useCookie.ts b/packages/extension/src/view/devtools/stateProviders/cookie/useCookie.ts
new file mode 100644
index 000000000..c1c215f3a
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/cookie/useCookie.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { useContextSelector } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import Context, { type CookieStoreContext } from './context';
+
+export function useCookie(): CookieStoreContext;
+export function useCookie(selector: (state: CookieStoreContext) => T): T;
+
+/**
+ * Cookie store hook.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useCookie(
+ selector: (state: CookieStoreContext) => T | CookieStoreContext = (state) =>
+ state
+) {
+ return useContextSelector(Context, selector);
+}
+
+export default useCookie;
diff --git a/packages/extension/src/view/devtools/stateProviders/index.ts b/packages/extension/src/view/devtools/stateProviders/index.ts
new file mode 100644
index 000000000..a2d1bc49c
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export * from './cookie';
+export * from './settings';
+export * from './allowedList';
diff --git a/packages/extension/src/view/devtools/stateProviders/settings/context.ts b/packages/extension/src/view/devtools/stateProviders/settings/context.ts
new file mode 100644
index 000000000..ab8b0cd26
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/settings/context.ts
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { noop, createContext } from '@ps-analysis-tool/common';
+
+export interface SettingsStoreContext {
+ state: {
+ allowedNumberOfTabs: string | null;
+ currentTabs: number;
+ currentExtensions:
+ | {
+ extensionName: string;
+ extensionId: string;
+ }[]
+ | null;
+ browserInformation: string | null;
+ OSInformation: string | null;
+ PSATVersion: string | null;
+ isUsingCDP: boolean;
+ settingsChanged: boolean;
+ allowedNumberOfTabsForSettingsPageDisplay: string | null;
+ isUsingCDPForSettingsPageDisplay: boolean;
+ };
+ actions: {
+ setProcessingMode: (newState: boolean) => void;
+ setIsUsingCDP: (newValue: boolean) => void;
+ handleSettingsChange: () => void;
+ setSettingsChanged: React.Dispatch>;
+ };
+}
+
+const initialState: SettingsStoreContext = {
+ state: {
+ allowedNumberOfTabs: null,
+ currentTabs: 0,
+ currentExtensions: null,
+ browserInformation: null,
+ OSInformation: null,
+ PSATVersion: null,
+ isUsingCDP: false,
+ settingsChanged: false,
+ allowedNumberOfTabsForSettingsPageDisplay: null,
+ isUsingCDPForSettingsPageDisplay: false,
+ },
+ actions: {
+ setIsUsingCDP: noop,
+ setProcessingMode: noop,
+ handleSettingsChange: noop,
+ setSettingsChanged: noop,
+ },
+};
+
+export default createContext(initialState);
diff --git a/packages/extension/src/view/devtools/stateProviders/settings/index.ts b/packages/extension/src/view/devtools/stateProviders/settings/index.ts
new file mode 100644
index 000000000..e8761d2c7
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/settings/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as SettingsProvider } from './settingsProvider';
+export { default as SettingsContext } from './context';
+export { default as useSettings } from './useSettings';
diff --git a/packages/extension/src/view/devtools/stateProviders/syncSettingsStore/index.tsx b/packages/extension/src/view/devtools/stateProviders/settings/settingsProvider.tsx
similarity index 71%
rename from packages/extension/src/view/devtools/stateProviders/syncSettingsStore/index.tsx
rename to packages/extension/src/view/devtools/stateProviders/settings/settingsProvider.tsx
index eee967a08..9c852a3a1 100644
--- a/packages/extension/src/view/devtools/stateProviders/syncSettingsStore/index.tsx
+++ b/packages/extension/src/view/devtools/stateProviders/settings/settingsProvider.tsx
@@ -16,14 +16,17 @@
/**
* External dependencies.
*/
-import { useContextSelector, createContext } from 'use-context-selector';
import React, {
type PropsWithChildren,
useEffect,
useState,
useCallback,
} from 'react';
-import { noop } from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies.
+ */
+import Context, { type SettingsStoreContext } from './context';
+import { SERVICE_WORKER_TABS_RELOAD_COMMAND } from '../../../../constants';
enum PLATFORM_OS_MAP {
mac = 'MacOS',
@@ -35,56 +38,7 @@ enum PLATFORM_OS_MAP {
fuchsia = 'Fuchsia',
}
-export interface SettingStoreContext {
- state: {
- allowedNumberOfTabs: string | null;
- currentTabs: number;
- currentExtensions:
- | {
- extensionName: string;
- extensionId: string;
- }[]
- | null;
- browserInformation: string | null;
- PSATVersion: string | null;
- OSInformation: string | null;
- isUsingCDP: boolean;
- settingsChanged: boolean;
- allowedNumberOfTabsForSettingsPageDisplay: string | null;
- isUsingCDPForSettingsPageDisplay: boolean;
- };
- actions: {
- setProcessingMode: (newState: boolean) => void;
- setIsUsingCDP: (newValue: boolean) => void;
- handleSettingsChange: () => void;
- setSettingsChanged: React.Dispatch>;
- };
-}
-
-const initialState: SettingStoreContext = {
- state: {
- allowedNumberOfTabs: null,
- currentTabs: 0,
- currentExtensions: null,
- browserInformation: null,
- PSATVersion: null,
- OSInformation: null,
- isUsingCDP: false,
- settingsChanged: false,
- allowedNumberOfTabsForSettingsPageDisplay: null,
- isUsingCDPForSettingsPageDisplay: false,
- },
- actions: {
- setIsUsingCDP: noop,
- setProcessingMode: noop,
- handleSettingsChange: noop,
- setSettingsChanged: noop,
- },
-};
-
-export const Context = createContext(initialState);
-
-export const Provider = ({ children }: PropsWithChildren) => {
+const Provider = ({ children }: PropsWithChildren) => {
const [allowedNumberOfTabs, setAllowedNumberOfTabs] = useState(
null
);
@@ -102,15 +56,16 @@ export const Provider = ({ children }: PropsWithChildren) => {
] = useState(false);
const [currentTabs, setCurrentTabs] =
- useState(0);
+ useState(0);
const [browserInformation, setBrowserInformation] = useState(
null
);
- const [PSATVersion, setPSATVersion] = useState(null);
+ const [PSATVersion, setPSATVersion] =
+ useState(null);
const [currentExtensions, setCurrentExtensions] =
- useState(null);
+ useState(null);
const [OSInformation, setOSInformation] =
- useState(null);
+ useState(null);
const intitialSync = useCallback(async () => {
const sessionStorage = await chrome.storage.session.get();
@@ -186,20 +141,20 @@ export const Provider = ({ children }: PropsWithChildren) => {
}
}, [OSInformation]);
- const setProcessingMode = useCallback((newState: boolean) => {
+ const setProcessingMode = useCallback(async (newState: boolean) => {
const valueToBeSet: boolean | string = newState ? 'unlimited' : 'single';
setAllowedNumberOfTabsForSettingsPageDisplay(valueToBeSet);
setSettingsChanged(true);
- chrome.storage.session.set({
+ await chrome.storage.session.set({
allowedNumberOfTabs: valueToBeSet,
pendingReload: true,
});
}, []);
- const _setUsingCDP = useCallback((newValue: boolean) => {
+ const _setUsingCDP = useCallback(async (newValue: boolean) => {
setIsUsingCDPForSettingsPageDisplay(newValue);
setSettingsChanged(true);
- chrome.storage.session.set({
+ await chrome.storage.session.set({
isUsingCDP: newValue,
pendingReload: true,
});
@@ -207,10 +162,7 @@ export const Provider = ({ children }: PropsWithChildren) => {
const storeChangeListener = useCallback(
(changes: { [key: string]: chrome.storage.StorageChange }) => {
- if (
- Object.keys(changes).includes('allowedNumberOfTabs') &&
- Object.keys(changes.allowedNumberOfTabs).includes('newValue')
- ) {
+ if (changes?.['allowedNumberOfTabs']?.['newValue']) {
setAllowedNumberOfTabs(changes?.allowedNumberOfTabs?.newValue);
setAllowedNumberOfTabsForSettingsPageDisplay(
changes?.allowedNumberOfTabs?.newValue
@@ -230,10 +182,7 @@ export const Provider = ({ children }: PropsWithChildren) => {
const sessionStoreChangeListener = useCallback(
(changes: { [key: string]: chrome.storage.StorageChange }) => {
- if (
- Object.keys(changes).includes('allowedNumberOfTabs') &&
- Object.keys(changes.allowedNumberOfTabs).includes('newValue')
- ) {
+ if (changes?.['allowedNumberOfTabs']?.['newValue']) {
setAllowedNumberOfTabsForSettingsPageDisplay(
changes.allowedNumberOfTabs.newValue
);
@@ -259,7 +208,7 @@ export const Provider = ({ children }: PropsWithChildren) => {
const handleSettingsChange = useCallback(async () => {
if (settingsChanged) {
await chrome.runtime.sendMessage({
- type: 'DevTools::ServiceWorker::RELOAD_ALL_TABS',
+ type: SERVICE_WORKER_TABS_RELOAD_COMMAND,
});
setSettingsChanged(false);
@@ -307,19 +256,4 @@ export const Provider = ({ children }: PropsWithChildren) => {
);
};
-export function useSettingsStore(): SettingStoreContext;
-export function useSettingsStore(
- selector: (state: SettingStoreContext) => T
-): T;
-
-/**
- * Cookie store hook.
- * @param selector Selector function to partially select state.
- * @returns selected part of the state
- */
-export function useSettingsStore(
- selector: (state: SettingStoreContext) => T | SettingStoreContext = (state) =>
- state
-) {
- return useContextSelector(Context, selector);
-}
+export default Provider;
diff --git a/packages/extension/src/view/devtools/stateProviders/settings/useSettings.ts b/packages/extension/src/view/devtools/stateProviders/settings/useSettings.ts
new file mode 100644
index 000000000..20807b751
--- /dev/null
+++ b/packages/extension/src/view/devtools/stateProviders/settings/useSettings.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import { useContextSelector } from '@ps-analysis-tool/common';
+/**
+ * Internal dependencies.
+ */
+import Context, { type SettingsStoreContext } from './context';
+
+export function useSettings(): SettingsStoreContext;
+export function useSettings(selector: (state: SettingsStoreContext) => T): T;
+
+/**
+ * Cookie store hook.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useSettings(
+ selector: (state: SettingsStoreContext) => T | SettingsStoreContext = (
+ state
+ ) => state
+) {
+ return useContextSelector(Context, selector);
+}
+
+export default useSettings;
diff --git a/packages/extension/src/view/devtools/tabs.ts b/packages/extension/src/view/devtools/tabs.ts
new file mode 100644
index 000000000..1d9c73b37
--- /dev/null
+++ b/packages/extension/src/view/devtools/tabs.ts
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import {
+ CookieIcon,
+ CookieIconWhite,
+ SiteBoundariesIcon,
+ SiteBoundariesIconWhite,
+ ChipsIcon,
+ ChipsIconWhite,
+ RelatedWebsiteSetsIcon,
+ RelatedWebsiteSetsIconWhite,
+ PrivateAdvertisingIcon,
+ PrivateAdvertisingIconWhite,
+ AntiCovertTrackingIcon,
+ AntiCovertTrackingIconWhite,
+ AttributionIcon,
+ AttributionIconWhite,
+ BounceTrackingIcon,
+ BounceTrackingIconWhite,
+ FingerPrintingIcon,
+ FingerPrintingIconWhite,
+ TopicsIcon,
+ TopicsIconWhite,
+ PrivacySandboxIcon,
+ PrivacySandboxIconWhite,
+ type SidebarItems,
+ InfoIcon,
+ SIDEBAR_ITEMS_KEYS,
+} from '@ps-analysis-tool/design-system';
+
+/**
+ * Internal dependencies.
+ */
+// @ts-ignore
+// eslint-disable-next-line import/no-relative-packages
+import SettingsTab from '../../../../../assets/icons/settings-tab.svg';
+// @ts-ignore
+// eslint-disable-next-line import/no-relative-packages
+import SettingsTabWhite from '../../../../../assets/icons/settings-tab-white.svg';
+import {
+ SiteBoundaries,
+ Chips,
+ RelatedWebsiteSets,
+ PrivateAdvertising,
+ AntiCovertTracking,
+ Topics,
+ Attribution,
+ BounceTracking,
+ Fingerprinting,
+ PrivacySandbox,
+ Settings,
+ FacilitatedTesting,
+} from './components';
+
+const TABS: SidebarItems = {
+ [SIDEBAR_ITEMS_KEYS.PRIVACY_SANDBOX]: {
+ title: 'Privacy Sandbox',
+ panel: {
+ Element: PrivacySandbox,
+ },
+ icon: {
+ Element: PrivacySandboxIcon,
+ },
+ selectedIcon: {
+ Element: PrivacySandboxIconWhite,
+ },
+ dropdownOpen: true,
+ children: {
+ [SIDEBAR_ITEMS_KEYS.COOKIES]: {
+ title: 'Cookies',
+ icon: {
+ Element: CookieIcon,
+ },
+ selectedIcon: {
+ Element: CookieIconWhite,
+ },
+ children: {},
+ dropdownOpen: true,
+ },
+ [SIDEBAR_ITEMS_KEYS.SITE_BOUNDARIES]: {
+ title: 'Site Boundaries',
+ panel: {
+ Element: SiteBoundaries,
+ },
+ icon: {
+ Element: SiteBoundariesIcon,
+ },
+ selectedIcon: {
+ Element: SiteBoundariesIconWhite,
+ },
+ children: {
+ [SIDEBAR_ITEMS_KEYS.CHIPS]: {
+ title: 'CHIPS',
+ panel: {
+ Element: Chips,
+ },
+ icon: {
+ Element: ChipsIcon,
+ },
+ selectedIcon: {
+ Element: ChipsIconWhite,
+ },
+ children: {},
+ },
+ [SIDEBAR_ITEMS_KEYS.RELATED_WEBSITE_SETS]: {
+ title: 'Related Website Sets',
+ panel: {
+ Element: RelatedWebsiteSets,
+ },
+ icon: {
+ Element: RelatedWebsiteSetsIcon,
+ },
+ selectedIcon: {
+ Element: RelatedWebsiteSetsIconWhite,
+ },
+ children: {},
+ },
+ },
+ },
+ [SIDEBAR_ITEMS_KEYS.PRIVATE_ADVERTISING]: {
+ title: 'Private Advertising',
+ panel: {
+ Element: PrivateAdvertising,
+ },
+ icon: {
+ Element: PrivateAdvertisingIcon,
+ },
+ selectedIcon: {
+ Element: PrivateAdvertisingIconWhite,
+ },
+ children: {
+ [SIDEBAR_ITEMS_KEYS.TOPICS]: {
+ title: 'Topics',
+ panel: {
+ Element: Topics,
+ },
+ icon: {
+ Element: TopicsIcon,
+ },
+ selectedIcon: {
+ Element: TopicsIconWhite,
+ },
+ children: {},
+ },
+ [SIDEBAR_ITEMS_KEYS.ATTRIBUTION]: {
+ title: 'Attribution',
+ panel: {
+ Element: Attribution,
+ },
+ icon: {
+ Element: AttributionIcon,
+ },
+ selectedIcon: {
+ Element: AttributionIconWhite,
+ },
+ children: {},
+ },
+ },
+ },
+ [SIDEBAR_ITEMS_KEYS.ANTI_COVERT_TRACKING]: {
+ title: 'Tracking Protection',
+ panel: {
+ Element: AntiCovertTracking,
+ },
+ icon: {
+ Element: AntiCovertTrackingIcon,
+ },
+ selectedIcon: {
+ Element: AntiCovertTrackingIconWhite,
+ },
+ children: {
+ [SIDEBAR_ITEMS_KEYS.BOUNCE_TRACKING]: {
+ title: 'Bounce Tracking',
+ panel: {
+ Element: BounceTracking,
+ },
+ icon: {
+ Element: BounceTrackingIcon,
+ },
+ selectedIcon: {
+ Element: BounceTrackingIconWhite,
+ },
+ children: {},
+ },
+ [SIDEBAR_ITEMS_KEYS.FINGERPRINTING]: {
+ title: 'Fingerprinting',
+ panel: {
+ Element: Fingerprinting,
+ },
+ icon: {
+ Element: FingerPrintingIcon,
+ },
+ selectedIcon: {
+ Element: FingerPrintingIconWhite,
+ },
+ children: {},
+ },
+ },
+ },
+ },
+ },
+ [SIDEBAR_ITEMS_KEYS.FACILITATED_TESTING]: {
+ title: 'Facilitated Testing',
+ panel: {
+ Element: FacilitatedTesting,
+ },
+ icon: {
+ Element: InfoIcon,
+ props: {
+ className: 'fill-gray',
+ },
+ },
+ selectedIcon: {
+ Element: InfoIcon,
+ props: {
+ className: 'fill-white',
+ },
+ },
+ dropdownOpen: false,
+ children: {},
+ },
+ [SIDEBAR_ITEMS_KEYS.SETTINGS]: {
+ title: 'Settings',
+ panel: {
+ Element: Settings,
+ },
+ icon: {
+ Element: SettingsTab,
+ },
+ selectedIcon: {
+ Element: SettingsTabWhite,
+ },
+ dropdownOpen: false,
+ children: {},
+ },
+};
+
+export default TABS;
diff --git a/packages/extension/src/view/devtools/tabs.tsx b/packages/extension/src/view/devtools/tabs.tsx
deleted file mode 100644
index 94c0c11e0..000000000
--- a/packages/extension/src/view/devtools/tabs.tsx
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * External dependencies
- */
-import React from 'react';
-import {
- CookieIcon,
- CookieIconWhite,
- SiteBoundariesIcon,
- SiteBoundariesIconWhite,
- ChipsIcon,
- ChipsIconWhite,
- RelatedWebsiteSetsIcon,
- RelatedWebsiteSetsIconWhite,
- PrivateAdvertisingIcon,
- PrivateAdvertisingIconWhite,
- AntiCovertTrackingIcon,
- AntiCovertTrackingIconWhite,
- AttributionIcon,
- AttributionIconWhite,
- BounceTrackingIcon,
- BounceTrackingIconWhite,
- FingerPrintingIcon,
- FingerPrintingIconWhite,
- TopicsIcon,
- TopicsIconWhite,
- PrivacySandboxIcon,
- PrivacySandboxIconWhite,
- type SidebarItems,
- InfoIcon,
-} from '@ps-analysis-tool/design-system';
-
-/**
- * Internal dependencies.
- */
-// @ts-ignore
-// eslint-disable-next-line import/no-relative-packages
-import SettingsTab from '../../../../../assets/icons/settings-tab.svg';
-// @ts-ignore
-// eslint-disable-next-line import/no-relative-packages
-import SettingsTabWhite from '../../../../../assets/icons/settings-tab-white.svg';
-import {
- SiteBoundaries,
- Chips,
- RelatedWebsiteSets,
- PrivateAdvertising,
- AntiCovertTracking,
- Topics,
- Attribution,
- BounceTracking,
- Fingerprinting,
- PrivacySandbox,
- Settings,
- FacilitatedTesting,
-} from './components';
-
-const TABS: SidebarItems = {
- privacySandbox: {
- title: 'Privacy Sandbox',
- panel: ,
- icon: ,
- selectedIcon: ,
- dropdownOpen: true,
- children: {
- cookies: {
- title: 'Cookies',
- icon: ,
- selectedIcon: ,
- children: {},
- dropdownOpen: true,
- },
- siteBoundaries: {
- title: 'Site Boundaries',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {
- chips: {
- title: 'CHIPS',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {},
- },
- relatedWebsiteSets: {
- title: 'Related Website Sets',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {},
- },
- },
- },
- privateAdvertising: {
- title: 'Private Advertising',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {
- topics: {
- title: 'Topics',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {},
- },
- attribution: {
- title: 'Attribution',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {},
- },
- },
- },
- antiCovertTracking: {
- title: 'Tracking Protection',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {
- bounceTracking: {
- title: 'Bounce Tracking',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {},
- },
- fingerprinting: {
- title: 'Fingerprinting',
- panel: ,
- icon: ,
- selectedIcon: ,
- children: {},
- },
- },
- },
- },
- },
- facilitatedTesting: {
- title: 'Facilitated Testing',
- panel: ,
- icon: ,
- selectedIcon: ,
- dropdownOpen: false,
- children: {},
- },
- settings: {
- title: 'Settings',
- panel: ,
- icon: ,
- selectedIcon: ,
- dropdownOpen: false,
- children: {},
- },
-};
-
-export default TABS;
diff --git a/packages/extension/src/view/devtools/tests/app.tsx b/packages/extension/src/view/devtools/tests/app.tsx
index 6d294f6e1..5ba5b9515 100644
--- a/packages/extension/src/view/devtools/tests/app.tsx
+++ b/packages/extension/src/view/devtools/tests/app.tsx
@@ -28,19 +28,15 @@ import { useTablePersistentSettingsStore } from '@ps-analysis-tool/design-system
* Internal dependencies.
*/
import App from '../app';
-import { useCookieStore } from '../stateProviders/syncCookieStore';
+import { useCookie, useSettings } from '../stateProviders';
// @ts-ignore
// eslint-disable-next-line import/no-unresolved
import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
import data from '../../../utils/test-data/cookieMockData';
-import { useSettingsStore } from '../stateProviders/syncSettingsStore';
-jest.mock('../stateProviders/syncCookieStore', () => ({
- useCookieStore: jest.fn(),
-}));
-
-jest.mock('../stateProviders/syncSettingsStore', () => ({
- useSettingsStore: jest.fn(),
+jest.mock('../stateProviders', () => ({
+ useCookie: jest.fn(),
+ useSettings: jest.fn(),
}));
jest.mock(
@@ -50,10 +46,10 @@ jest.mock(
})
);
-const mockUseCookieStore = useCookieStore as jest.Mock;
+const mockUseCookieStore = useCookie as jest.Mock;
const mockUseTablePersistentSettingStore =
useTablePersistentSettingsStore as jest.Mock;
-const mockUseSettingsStore = useSettingsStore as jest.Mock;
+const mockUseSettingsStore = useSettings as jest.Mock;
describe('App', () => {
beforeAll(() => {
@@ -110,7 +106,10 @@ describe('App', () => {
session: {
//@ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- get: (_, __) => Promise.resolve(),
+ get: (_, __) =>
+ Promise.resolve({
+ ['selectedSidebarItem#' + 40245632]: 'privacySandbox#cookies',
+ }),
set: () => Promise.resolve(),
//@ts-ignore
onChanged: {
diff --git a/packages/extension/src/view/popup/app.tsx b/packages/extension/src/view/popup/app.tsx
index fee095e8c..63ff291eb 100644
--- a/packages/extension/src/view/popup/app.tsx
+++ b/packages/extension/src/view/popup/app.tsx
@@ -32,7 +32,7 @@ import {
*/
import './app.css';
import { Legend } from './components';
-import { useCookieStore } from './stateProviders/syncCookieStore';
+import { useCookie, useSettings } from './stateProviders';
import { ALLOWED_NUMBER_OF_TABS } from '../../constants';
const App: React.FC = () => {
@@ -40,25 +40,29 @@ const App: React.FC = () => {
cookieStats,
loading,
isCurrentTabBeingListenedTo,
- changeListeningToThisTab,
onChromeUrl,
- allowedNumberOfTabs,
- isUsingCDP,
- setIsUsingCDP,
- settingsChanged,
- handleSettingsChange,
- } = useCookieStore(({ state, actions }) => ({
+ changeListeningToThisTab,
+ } = useCookie(({ state, actions }) => ({
cookieStats: state.tabCookieStats,
isCurrentTabBeingListenedTo: state.isCurrentTabBeingListenedTo,
loading: state.loading,
returningToSingleTab: state.returningToSingleTab,
- allowedNumberOfTabs: state.allowedNumberOfTabs,
onChromeUrl: state.onChromeUrl,
+ changeListeningToThisTab: actions.changeListeningToThisTab,
+ }));
+
+ const {
+ allowedNumberOfTabs,
+ isUsingCDP,
+ settingsChanged,
+ setUsingCDP,
+ handleSettingsChange,
+ } = useSettings(({ state, actions }) => ({
+ allowedNumberOfTabs: state.allowedNumberOfTabs,
isUsingCDP: state.isUsingCDPForSettingsDisplay,
- setIsUsingCDP: actions.setIsUsingCDP,
- handleSettingsChange: actions.handleSettingsChange,
settingsChanged: state.settingsChanged,
- changeListeningToThisTab: actions.changeListeningToThisTab,
+ setUsingCDP: actions.setUsingCDP,
+ handleSettingsChange: actions.handleSettingsChange,
}));
const cdpLabel = isUsingCDP ? 'Disable CDP' : 'Enable CDP';
@@ -69,7 +73,7 @@ const App: React.FC = () => {
Not much to analyze here
@@ -111,7 +115,7 @@ const App: React.FC = () => {
@@ -138,7 +142,7 @@ const App: React.FC = () => {
No cookies found on this page
@@ -165,7 +169,7 @@ const App: React.FC = () => {
diff --git a/packages/extension/src/view/popup/index.tsx b/packages/extension/src/view/popup/index.tsx
index a7b026868..c0ffb61eb 100644
--- a/packages/extension/src/view/popup/index.tsx
+++ b/packages/extension/src/view/popup/index.tsx
@@ -24,16 +24,18 @@ import { createRoot } from 'react-dom/client';
* Internal dependencies.
*/
import App from './app';
-import { Provider as ExternalStoreProvider } from './stateProviders/syncCookieStore';
+import { CookieProvider, SettingsProvider } from './stateProviders';
const root = document.getElementById('root');
if (root) {
createRoot(root).render(
-
-
-
+
+
+
+
+
);
}
diff --git a/packages/extension/src/view/popup/stateProviders/cookie/context.ts b/packages/extension/src/view/popup/stateProviders/cookie/context.ts
new file mode 100644
index 000000000..d58850a99
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/cookie/context.ts
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import {
+ noop,
+ createContext,
+ type CookiesCount,
+} from '@ps-analysis-tool/common';
+
+export interface CookieStoreContext {
+ state: {
+ tabCookieStats: CookiesCount | null;
+ isCurrentTabBeingListenedTo: boolean;
+ loading: boolean;
+ returningToSingleTab: boolean;
+ tabId: number | null;
+ onChromeUrl: boolean;
+ };
+ actions: {
+ changeListeningToThisTab: () => void;
+ };
+}
+
+const initialState: CookieStoreContext = {
+ state: {
+ tabCookieStats: {
+ total: 0,
+ blockedCookies: {
+ total: 0,
+ },
+ firstParty: {
+ total: 0,
+ functional: 0,
+ marketing: 0,
+ analytics: 0,
+ uncategorized: 0,
+ },
+ thirdParty: {
+ total: 0,
+ functional: 0,
+ marketing: 0,
+ analytics: 0,
+ uncategorized: 0,
+ },
+ },
+ isCurrentTabBeingListenedTo: false,
+ loading: true,
+ returningToSingleTab: false,
+ onChromeUrl: false,
+ tabId: null,
+ },
+ actions: {
+ changeListeningToThisTab: noop,
+ },
+};
+
+export default createContext
(initialState);
diff --git a/packages/extension/src/view/popup/stateProviders/cookie/cookieProvider.tsx b/packages/extension/src/view/popup/stateProviders/cookie/cookieProvider.tsx
new file mode 100644
index 000000000..ca3a3d7e2
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/cookie/cookieProvider.tsx
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React, {
+ type PropsWithChildren,
+ useEffect,
+ useState,
+ useCallback,
+ useRef,
+} from 'react';
+import { useDebouncedCallback } from 'use-debounce';
+import { prepareCookiesCount } from '@ps-analysis-tool/design-system';
+import { type CookieData } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import { getCurrentTab } from '../../../../utils/getCurrentTabId';
+import {
+ ALLOWED_NUMBER_OF_TABS,
+ INITIAL_SYNC,
+ NEW_COOKIE_DATA,
+ POPUP_CLOSE,
+ POPUP_OPEN,
+ SERVICE_WORKER_RELOAD_MESSAGE,
+ SET_TAB_TO_READ,
+} from '../../../../constants';
+import { useSettings } from '../settings';
+import Context, { type CookieStoreContext } from './context';
+
+const Provider = ({ children }: PropsWithChildren) => {
+ const [tabId, setTabId] = useState(null);
+
+ const [tabToRead, setTabToRead] = useState(null);
+ const [tabCookieStats, setTabCookieStats] =
+ useState(null);
+
+ const [returningToSingleTab, setReturningToSingleTab] =
+ useState(false);
+
+ const [loading, setLoading] = useState(true);
+
+ const [isCurrentTabBeingListenedTo, setIsCurrentTabBeingListenedTo] =
+ useState(false);
+
+ const [onChromeUrl, setOnChromeUrl] = useState(false);
+
+ const loadingTimeout = useRef | null>(null);
+
+ const { setSettingsChanged } = useSettings(({ actions }) => ({
+ setSettingsChanged: actions.setSettingsChanged,
+ }));
+
+ useEffect(() => {
+ loadingTimeout.current = setTimeout(() => {
+ setLoading(false);
+ }, 6500);
+
+ return () => {
+ if (loadingTimeout.current) {
+ clearTimeout(loadingTimeout.current);
+ }
+ };
+ }, []);
+
+ const setDebouncedStats = useDebouncedCallback((value) => {
+ setTabCookieStats(value);
+ setLoading(false);
+ }, 100);
+
+ const intitialSync = useCallback(async () => {
+ const tab = await getCurrentTab();
+
+ const availableTabs = await chrome.tabs.query({});
+
+ if (
+ availableTabs.length === ALLOWED_NUMBER_OF_TABS &&
+ availableTabs.filter(
+ (processingTab) => processingTab.id?.toString() === tabToRead
+ )
+ ) {
+ setReturningToSingleTab(true);
+ }
+
+ if (!tab || !tab[0].id || !tab[0].url) {
+ return;
+ }
+
+ if (tab[0].url.startsWith('chrome:')) {
+ setOnChromeUrl(true);
+ } else {
+ setOnChromeUrl(false);
+ }
+
+ setTabId(tab[0].id);
+ }, [tabToRead]);
+
+ useEffect(() => {
+ chrome.runtime.sendMessage({
+ type: POPUP_OPEN,
+ payload: {
+ tabId: tabId,
+ },
+ });
+
+ return () => {
+ chrome.runtime.sendMessage({
+ type: POPUP_CLOSE,
+ payload: {
+ tabId: tabId,
+ },
+ });
+ };
+ }, [tabId]);
+
+ const changeListeningToThisTab = useCallback(() => {
+ chrome.runtime.sendMessage({
+ type: SET_TAB_TO_READ,
+ payload: {
+ tabId,
+ },
+ });
+ }, [tabId]);
+
+ useEffect(() => {
+ const listener = (message: {
+ type: string;
+ payload: {
+ tabId?: number;
+ cookieData?: { [key: string]: CookieData };
+ tabToRead?: string;
+ tabProcessingMode?: string;
+ isUsingCDPNewValue?: boolean;
+ tabMode?: string;
+ };
+ }) => {
+ if (!message.type) {
+ return;
+ }
+
+ const incomingMessageType = message.type;
+
+ if (SET_TAB_TO_READ === incomingMessageType) {
+ setTabToRead(message?.payload?.tabId?.toString() || null);
+ setIsCurrentTabBeingListenedTo(true);
+ setLoading(false);
+ }
+
+ if (NEW_COOKIE_DATA === incomingMessageType) {
+ if (
+ message?.payload?.tabId &&
+ tabId?.toString() === message?.payload?.tabId.toString()
+ ) {
+ setTabCookieStats(
+ prepareCookiesCount(message?.payload?.cookieData ?? null)
+ );
+ setLoading(false);
+ }
+ }
+
+ if (INITIAL_SYNC === incomingMessageType) {
+ if (message?.payload?.tabMode === 'unlimited') {
+ setIsCurrentTabBeingListenedTo(true);
+ setTabToRead(null);
+ } else {
+ setIsCurrentTabBeingListenedTo(
+ tabId?.toString() === message?.payload?.tabToRead
+ );
+ setTabToRead(message?.payload?.tabToRead || null);
+ }
+ setLoading(false);
+ }
+
+ if (SERVICE_WORKER_RELOAD_MESSAGE === incomingMessageType) {
+ setSettingsChanged(false);
+ }
+ };
+
+ chrome.runtime.onMessage.addListener(listener);
+
+ return () => {
+ chrome.runtime.onMessage.removeListener(listener);
+ };
+ }, [setDebouncedStats, tabId, setSettingsChanged]);
+
+ useEffect(() => {
+ intitialSync();
+ }, [intitialSync]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default Provider;
diff --git a/packages/extension/src/view/popup/stateProviders/cookie/index.ts b/packages/extension/src/view/popup/stateProviders/cookie/index.ts
new file mode 100644
index 000000000..ec0295af0
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/cookie/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as CookieProvider } from './cookieProvider';
+export { default as CookieContext } from './context';
+export { default as useCookie } from './useCookie';
diff --git a/packages/extension/src/view/popup/stateProviders/cookie/useCookie.ts b/packages/extension/src/view/popup/stateProviders/cookie/useCookie.ts
new file mode 100644
index 000000000..e6e3b8c1e
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/cookie/useCookie.ts
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import { useContextSelector } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import Context, { type CookieStoreContext } from './context';
+
+export function useCookie(): CookieStoreContext;
+export function useCookie(selector: (state: CookieStoreContext) => T): T;
+
+/**
+ * Cookie store hook.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useCookie(
+ selector: (state: CookieStoreContext) => T | CookieStoreContext = (state) =>
+ state
+) {
+ return useContextSelector(Context, selector);
+}
+
+export default useCookie;
diff --git a/packages/extension/src/view/popup/stateProviders/index.ts b/packages/extension/src/view/popup/stateProviders/index.ts
new file mode 100644
index 000000000..9dc63ead5
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export * from './cookie';
+export * from './settings';
diff --git a/packages/extension/src/view/popup/stateProviders/settings/context.ts b/packages/extension/src/view/popup/stateProviders/settings/context.ts
new file mode 100644
index 000000000..188daafea
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/settings/context.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { noop, createContext } from '@ps-analysis-tool/common';
+
+export interface SettingsStoreContext {
+ state: {
+ allowedNumberOfTabs: string | null;
+ isUsingCDP: boolean;
+ settingsChanged: boolean;
+ allowedNumberOfTabsForSettingsDisplay: string | null;
+ isUsingCDPForSettingsDisplay: boolean;
+ };
+ actions: {
+ handleSettingsChange: () => void;
+ setUsingCDP: (newValue: boolean) => void;
+ setSettingsChanged: (newValue: boolean) => void;
+ };
+}
+
+const initialState: SettingsStoreContext = {
+ state: {
+ allowedNumberOfTabs: null,
+ isUsingCDP: false,
+ settingsChanged: false,
+ allowedNumberOfTabsForSettingsDisplay: null,
+ isUsingCDPForSettingsDisplay: false,
+ },
+ actions: {
+ handleSettingsChange: noop,
+ setUsingCDP: noop,
+ setSettingsChanged: noop,
+ },
+};
+
+export default createContext(initialState);
diff --git a/packages/extension/src/view/popup/stateProviders/settings/index.ts b/packages/extension/src/view/popup/stateProviders/settings/index.ts
new file mode 100644
index 000000000..e8761d2c7
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/settings/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as SettingsProvider } from './settingsProvider';
+export { default as SettingsContext } from './context';
+export { default as useSettings } from './useSettings';
diff --git a/packages/extension/src/view/popup/stateProviders/settings/settingsProvider.tsx b/packages/extension/src/view/popup/stateProviders/settings/settingsProvider.tsx
new file mode 100644
index 000000000..b87c3a503
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/settings/settingsProvider.tsx
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React, {
+ type PropsWithChildren,
+ useEffect,
+ useState,
+ useCallback,
+} from 'react';
+
+/**
+ * Internal dependencies
+ */
+import Context from './context';
+import { SERVICE_WORKER_TABS_RELOAD_COMMAND } from '../../../../constants';
+
+const Provider = ({ children }: PropsWithChildren) => {
+ const [allowedNumberOfTabs, setAllowedNumberOfTabs] = useState(
+ null
+ );
+ const [
+ allowedNumberOfTabsForSettingsDisplay,
+ setAllowedNumberOfTabsForSettingsDisplay,
+ ] = useState(null);
+
+ const [settingsChanged, setSettingsChanged] = useState(false);
+
+ const [isUsingCDP, _setIsUsingCDP] = useState(false);
+ const [isUsingCDPForSettingsDisplay, setIsUsingCDPForSettingsDisplay] =
+ useState(false);
+
+ const intitialSync = useCallback(async () => {
+ const sessionStorage = await chrome.storage.session.get();
+ const currentSettings = await chrome.storage.sync.get();
+
+ if (Object.keys(sessionStorage).includes('pendingReload')) {
+ setSettingsChanged(sessionStorage?.pendingReload);
+
+ if (Object.keys(sessionStorage).includes('allowedNumberOfTabs')) {
+ setAllowedNumberOfTabsForSettingsDisplay(
+ sessionStorage.allowedNumberOfTabs
+ );
+ } else {
+ setAllowedNumberOfTabsForSettingsDisplay(
+ currentSettings.allowedNumberOfTabs
+ );
+ }
+
+ if (Object.keys(sessionStorage).includes('isUsingCDP')) {
+ setIsUsingCDPForSettingsDisplay(sessionStorage.isUsingCDP);
+ } else {
+ setIsUsingCDPForSettingsDisplay(currentSettings.isUsingCDP);
+ }
+ } else {
+ setAllowedNumberOfTabsForSettingsDisplay(
+ currentSettings.allowedNumberOfTabs
+ );
+ setIsUsingCDPForSettingsDisplay(currentSettings.isUsingCDP);
+ }
+
+ if (Object.keys(currentSettings).includes('allowedNumberOfTabs')) {
+ setAllowedNumberOfTabs(currentSettings.allowedNumberOfTabs);
+ }
+
+ if (Object.keys(currentSettings).includes('isUsingCDP')) {
+ _setIsUsingCDP(currentSettings.isUsingCDP);
+ }
+ }, []);
+
+ const setUsingCDP = useCallback(async (newValue: boolean) => {
+ setIsUsingCDPForSettingsDisplay(newValue);
+ await chrome.storage.session.set({
+ isUsingCDP: newValue,
+ pendingReload: true,
+ });
+ }, []);
+
+ const sessionStoreChangeListener = useCallback(
+ (changes: { [key: string]: chrome.storage.StorageChange }) => {
+ if (changes?.['allowedNumberOfTabs']?.['newValue']) {
+ setAllowedNumberOfTabsForSettingsDisplay(
+ changes?.allowedNumberOfTabs?.newValue
+ );
+ setSettingsChanged(true);
+ }
+
+ if (
+ Object.keys(changes).includes('isUsingCDP') &&
+ Object.keys(changes.isUsingCDP).includes('newValue')
+ ) {
+ setIsUsingCDPForSettingsDisplay(changes?.isUsingCDP?.newValue);
+ setSettingsChanged(true);
+ }
+ },
+ []
+ );
+
+ const handleSettingsChange = useCallback(async () => {
+ if (settingsChanged) {
+ await chrome.runtime.sendMessage({
+ type: SERVICE_WORKER_TABS_RELOAD_COMMAND,
+ });
+ setSettingsChanged(false);
+ }
+ }, [settingsChanged]);
+
+ const changeSyncStorageListener = useCallback(
+ (changes: { [key: string]: chrome.storage.StorageChange }) => {
+ if (changes?.['allowedNumberOfTabs']?.['newValue']) {
+ setAllowedNumberOfTabs(changes?.allowedNumberOfTabs?.newValue);
+ }
+
+ if (
+ Object.keys(changes).includes('isUsingCDP') &&
+ Object.keys(changes.isUsingCDP).includes('newValue')
+ ) {
+ _setIsUsingCDP(changes?.isUsingCDP?.newValue);
+ }
+ },
+ []
+ );
+
+ useEffect(() => {
+ intitialSync();
+ }, [intitialSync]);
+
+ useEffect(() => {
+ chrome.storage.sync.onChanged.addListener(changeSyncStorageListener);
+ chrome.storage.session.onChanged.addListener(sessionStoreChangeListener);
+
+ return () => {
+ chrome.storage.sync.onChanged.removeListener(changeSyncStorageListener);
+ chrome.storage.session.onChanged.removeListener(
+ sessionStoreChangeListener
+ );
+ };
+ }, [changeSyncStorageListener, sessionStoreChangeListener]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default Provider;
diff --git a/packages/extension/src/view/popup/stateProviders/settings/useSettings.ts b/packages/extension/src/view/popup/stateProviders/settings/useSettings.ts
new file mode 100644
index 000000000..a6f621a68
--- /dev/null
+++ b/packages/extension/src/view/popup/stateProviders/settings/useSettings.ts
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import { useContextSelector } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies.
+ */
+import Context, { type SettingsStoreContext } from './context';
+
+export function useSettings(): SettingsStoreContext;
+export function useSettings(selector: (state: SettingsStoreContext) => T): T;
+
+/**
+ * Cookie store hook.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useSettings(
+ selector: (state: SettingsStoreContext) => T | SettingsStoreContext = (
+ state
+ ) => state
+) {
+ return useContextSelector(Context, selector);
+}
+
+export default useSettings;
diff --git a/packages/extension/src/view/popup/stateProviders/syncCookieStore/index.tsx b/packages/extension/src/view/popup/stateProviders/syncCookieStore/index.tsx
deleted file mode 100644
index c457756e2..000000000
--- a/packages/extension/src/view/popup/stateProviders/syncCookieStore/index.tsx
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Copyright 2023 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * External dependencies.
- */
-import { useContextSelector, createContext } from 'use-context-selector';
-import React, {
- type PropsWithChildren,
- useEffect,
- useState,
- useCallback,
- useRef,
-} from 'react';
-import { useDebouncedCallback } from 'use-debounce';
-import { noop, prepareCookiesCount } from '@ps-analysis-tool/design-system';
-import { type CookieData, type CookiesCount } from '@ps-analysis-tool/common';
-
-/**
- * Internal dependencies.
- */
-import { getCurrentTab } from '../../../../utils/getCurrentTabId';
-import { ALLOWED_NUMBER_OF_TABS } from '../../../../constants';
-
-export interface CookieStoreContext {
- state: {
- tabCookieStats: CookiesCount | null;
- isCurrentTabBeingListenedTo: boolean;
- loading: boolean;
- returningToSingleTab: boolean;
- tabId: number | null;
- onChromeUrl: boolean;
- allowedNumberOfTabs: string | null;
- isUsingCDP: boolean;
- settingsChanged: boolean;
- allowedNumberOfTabsForSettingsDisplay: string | null;
- isUsingCDPForSettingsDisplay: boolean;
- };
- actions: {
- handleSettingsChange: () => void;
- changeListeningToThisTab: () => void;
- setIsUsingCDP: (newValue: boolean) => void;
- };
-}
-
-const initialState: CookieStoreContext = {
- state: {
- tabCookieStats: {
- total: 0,
- blockedCookies: {
- total: 0,
- },
- firstParty: {
- total: 0,
- functional: 0,
- marketing: 0,
- analytics: 0,
- uncategorized: 0,
- },
- thirdParty: {
- total: 0,
- functional: 0,
- marketing: 0,
- analytics: 0,
- uncategorized: 0,
- },
- },
- isCurrentTabBeingListenedTo: false,
- loading: true,
- returningToSingleTab: false,
- onChromeUrl: false,
- tabId: null,
- allowedNumberOfTabs: null,
- isUsingCDP: false,
- settingsChanged: false,
- allowedNumberOfTabsForSettingsDisplay: null,
- isUsingCDPForSettingsDisplay: false,
- },
- actions: {
- handleSettingsChange: noop,
- changeListeningToThisTab: noop,
- setIsUsingCDP: noop,
- },
-};
-
-export const Context = createContext(initialState);
-
-export const Provider = ({ children }: PropsWithChildren) => {
- const [tabId, setTabId] = useState(null);
-
- const [allowedNumberOfTabs, setAllowedNumberOfTabs] = useState(
- null
- );
- const [
- allowedNumberOfTabsForSettingsDisplay,
- setAllowedNumberOfTabsForSettingsDisplay,
- ] = useState(null);
-
- const [settingsChanged, setSettingsChanged] = useState(false);
-
- const [tabToRead, setTabToRead] = useState('');
- const [isUsingCDP, setIsUsingCDP] = useState(false);
- const [isUsingCDPForSettingsDisplay, setIsUsingCDPForSettingsDisplay] =
- useState(false);
-
- const [tabCookieStats, setTabCookieStats] =
- useState(null);
-
- const [returningToSingleTab, setReturningToSingleTab] =
- useState(false);
-
- const [loading, setLoading] = useState(true);
-
- const [isCurrentTabBeingListenedTo, setIsCurrentTabBeingListenedTo] =
- useState(false);
-
- const [onChromeUrl, setOnChromeUrl] = useState(false);
- const loadingTimeout = useRef | null>(null);
-
- useEffect(() => {
- loadingTimeout.current = setTimeout(() => {
- setLoading(false);
- }, 6500);
-
- return () => {
- if (loadingTimeout.current) {
- clearTimeout(loadingTimeout.current);
- }
- };
- }, []);
-
- const setDebouncedStats = useDebouncedCallback((value) => {
- setTabCookieStats(value);
- setLoading(false);
- }, 100);
-
- const _setUsingCDP = useCallback((newValue: boolean) => {
- setIsUsingCDPForSettingsDisplay(newValue);
- chrome.storage.session.set({
- isUsingCDP: newValue,
- pendingReload: true,
- });
- }, []);
-
- const intitialSync = useCallback(async () => {
- const sessionStorage = await chrome.storage.session.get();
- const currentSettings = await chrome.storage.sync.get();
-
- if (Object.keys(sessionStorage).includes('pendingReload')) {
- setSettingsChanged(sessionStorage?.pendingReload);
-
- if (Object.keys(sessionStorage).includes('allowedNumberOfTabs')) {
- setAllowedNumberOfTabsForSettingsDisplay(
- sessionStorage.allowedNumberOfTabs
- );
- } else {
- setAllowedNumberOfTabsForSettingsDisplay(
- currentSettings.allowedNumberOfTabs
- );
- }
-
- if (Object.keys(sessionStorage).includes('isUsingCDP')) {
- setIsUsingCDPForSettingsDisplay(sessionStorage.isUsingCDP);
- } else {
- setIsUsingCDPForSettingsDisplay(currentSettings.isUsingCDP);
- }
- } else {
- setAllowedNumberOfTabsForSettingsDisplay(
- currentSettings.allowedNumberOfTabs
- );
- setIsUsingCDPForSettingsDisplay(currentSettings.isUsingCDP);
- }
-
- if (Object.keys(currentSettings).includes('allowedNumberOfTabs')) {
- setAllowedNumberOfTabs(currentSettings.allowedNumberOfTabs);
- }
-
- if (Object.keys(currentSettings).includes('isUsingCDP')) {
- setIsUsingCDP(currentSettings.isUsingCDP);
- }
-
- const tab = await getCurrentTab();
-
- const availableTabs = await chrome.tabs.query({});
-
- if (
- availableTabs.length === ALLOWED_NUMBER_OF_TABS &&
- availableTabs.filter(
- (processingTab) => processingTab.id?.toString() === tabToRead
- )
- ) {
- setReturningToSingleTab(true);
- }
-
- if (!tab || !tab[0].id || !tab[0].url) {
- return;
- }
-
- if (tab[0].url.startsWith('chrome:')) {
- setOnChromeUrl(true);
- } else {
- setOnChromeUrl(false);
- }
-
- setTabId(tab[0].id);
- }, [tabToRead]);
-
- useEffect(() => {
- chrome.runtime.sendMessage({
- type: 'Popup::ServiceWorker::POPUP_STATE_OPEN',
- payload: {
- tabId: tabId,
- },
- });
-
- return () => {
- chrome.runtime.sendMessage({
- type: 'Popup::ServiceWorker::POPUP_STATE_CLOSE',
- payload: {
- tabId: tabId,
- },
- });
- };
- }, [tabId]);
-
- const changeListeningToThisTab = useCallback(() => {
- chrome.runtime.sendMessage({
- type: 'Popup::ServiceWorker::SET_TAB_TO_READ',
- payload: {
- tabId,
- },
- });
- }, [tabId]);
-
- const sessionStoreChangeListener = useCallback(
- (changes: { [key: string]: chrome.storage.StorageChange }) => {
- if (changes?.['allowedNumberOfTabs']?.['newValue']) {
- setAllowedNumberOfTabsForSettingsDisplay(
- changes?.allowedNumberOfTabs?.newValue
- );
- setSettingsChanged(true);
- }
-
- if (
- Object.keys(changes).includes('isUsingCDP') &&
- Object.keys(changes.isUsingCDP).includes('newValue')
- ) {
- setIsUsingCDPForSettingsDisplay(changes?.isUsingCDP?.newValue);
- setSettingsChanged(true);
- }
- },
- []
- );
-
- const handleSettingsChange = useCallback(async () => {
- if (settingsChanged) {
- await chrome.runtime.sendMessage({
- type: 'Popup::ServiceWorker::RELOAD_ALL_TABS',
- });
- setSettingsChanged(false);
- }
- }, [settingsChanged]);
-
- useEffect(() => {
- const listener = (message: {
- type: string;
- payload: {
- tabId?: string;
- cookieData?: { [key: string]: CookieData };
- tabToRead?: string;
- tabProcessingMode?: string;
- isUsingCDPNewValue?: boolean;
- tabMode?: string;
- };
- }) => {
- if (message.type === 'ServiceWorker::SET_TAB_TO_READ') {
- setTabToRead(message?.payload?.tabId || '');
- setIsCurrentTabBeingListenedTo(true);
- setLoading(false);
- }
-
- if (
- message.type === 'ServiceWorker::Popup::CHANGE_CDP_SETTING' &&
- typeof message?.payload?.isUsingCDPNewValue !== 'undefined'
- ) {
- setIsUsingCDP(message?.payload?.isUsingCDPNewValue);
- }
-
- if (message.type === 'ServiceWorker::Popup::NEW_COOKIE_DATA') {
- if (
- message?.payload?.tabId &&
- tabId?.toString() === message?.payload?.tabId.toString()
- ) {
- setTabCookieStats(
- prepareCookiesCount(message?.payload?.cookieData ?? null)
- );
- setLoading(false);
- }
- }
-
- if (message.type === 'ServiceWorker::Popup::INITIAL_SYNC') {
- if (message?.payload?.tabMode === 'unlimited') {
- setIsCurrentTabBeingListenedTo(true);
- setTabToRead('');
- } else {
- setIsCurrentTabBeingListenedTo(
- tabId?.toString() === message?.payload?.tabToRead
- );
- setTabToRead(message?.payload?.tabToRead || '');
- }
- setLoading(false);
- }
-
- if (message.type === 'ServiceWorker::TABS_RELOADED') {
- setSettingsChanged(false);
- }
- };
-
- chrome.runtime.onMessage.addListener(listener);
-
- return () => {
- chrome.runtime.onMessage.removeListener(listener);
- };
- }, [setDebouncedStats, tabId, allowedNumberOfTabs]);
-
- const changeSyncStorageListener = useCallback(
- (changes: { [key: string]: chrome.storage.StorageChange }) => {
- if (
- Object.keys(changes).includes('allowedNumberOfTabs') &&
- Object.keys(changes.allowedNumberOfTabs).includes('newValue')
- ) {
- setAllowedNumberOfTabs(changes?.allowedNumberOfTabs?.newValue);
- setAllowedNumberOfTabsForSettingsDisplay(
- changes?.allowedNumberOfTabs?.newValue
- );
- }
-
- if (
- Object.keys(changes).includes('isUsingCDP') &&
- Object.keys(changes.isUsingCDP).includes('newValue')
- ) {
- setIsUsingCDP(changes?.isUsingCDP?.newValue);
- setIsUsingCDPForSettingsDisplay(changes?.isUsingCDP?.newValue);
- }
- },
- []
- );
-
- useEffect(() => {
- intitialSync();
- }, [intitialSync]);
-
- useEffect(() => {
- chrome.storage.sync.onChanged.addListener(changeSyncStorageListener);
- chrome.storage.session.onChanged.addListener(sessionStoreChangeListener);
-
- return () => {
- chrome.storage.sync.onChanged.removeListener(changeSyncStorageListener);
- chrome.storage.session.onChanged.removeListener(
- sessionStoreChangeListener
- );
- };
- }, [changeSyncStorageListener, sessionStoreChangeListener]);
-
- return (
-
- {children}
-
- );
-};
-
-export function useCookieStore(): CookieStoreContext;
-export function useCookieStore(
- selector: (state: CookieStoreContext) => T
-): T;
-
-/**
- * Cookie store hook.
- * @param selector Selector function to partially select state.
- * @returns selected part of the state
- */
-export function useCookieStore(
- selector: (state: CookieStoreContext) => T | CookieStoreContext = (state) =>
- state
-) {
- return useContextSelector(Context, selector);
-}
diff --git a/packages/extension/src/view/popup/stories/app.stories.tsx b/packages/extension/src/view/popup/stories/app.stories.tsx
index e9e13f605..366b279ca 100644
--- a/packages/extension/src/view/popup/stories/app.stories.tsx
+++ b/packages/extension/src/view/popup/stories/app.stories.tsx
@@ -23,7 +23,7 @@ import type { Meta, StoryObj } from '@storybook/react';
* Internal dependencies.
*/
import App from '../app';
-import { Provider as ExternalStoreProvider } from '../stateProviders/syncCookieStore';
+import { Provider as ExternalStoreProvider } from '../stateProviders/cookie';
const meta: Meta = {
title: 'Extension/Popup/Page',
diff --git a/packages/extension/src/view/popup/tests/app.tsx b/packages/extension/src/view/popup/tests/app.tsx
index 85fa26b7e..82c96e2c1 100644
--- a/packages/extension/src/view/popup/tests/app.tsx
+++ b/packages/extension/src/view/popup/tests/app.tsx
@@ -26,16 +26,16 @@ import SinonChrome from 'sinon-chrome';
* Internal dependencies.
*/
import App from '../app';
-import { useCookieStore } from '../stateProviders/syncCookieStore';
+import { useCookie } from '../stateProviders';
// @ts-ignore
// eslint-disable-next-line import/no-unresolved
import PSInfo from 'ps-analysis-tool/data/PSInfo.json';
-jest.mock('../stateProviders/syncCookieStore', () => ({
- useCookieStore: jest.fn(),
+jest.mock('../stateProviders/cookie', () => ({
+ useCookie: jest.fn(),
}));
-const mockUseCookieStore = useCookieStore as jest.Mock;
+const mockUseCookieStore = useCookie as jest.Mock;
describe('App', () => {
beforeAll(() => {
@@ -65,6 +65,17 @@ describe('App', () => {
).toBeInTheDocument();
});
+ it('Should show loader', () => {
+ mockUseCookieStore.mockReturnValueOnce({
+ loading: true,
+ });
+ act(() => {
+ render( );
+ });
+
+ expect(screen.getByTestId('progress-bar')).toBeInTheDocument();
+ });
+
it('Should show No cookies found on this page message if no firstParty and thirdParty cookies are not available', () => {
mockUseCookieStore.mockReturnValueOnce({
isCurrentTabBeingListenedTo: true,
@@ -97,6 +108,9 @@ describe('App', () => {
blockedCookies: {
total: 0,
},
+ exemptedCookies: {
+ total: 0,
+ },
firstParty: {
total: 3,
analytics: 1,
diff --git a/packages/extension/src/view/report/app.css b/packages/extension/src/view/report/app.css
new file mode 100644
index 000000000..b5c61c956
--- /dev/null
+++ b/packages/extension/src/view/report/app.css
@@ -0,0 +1,3 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/packages/extension/src/view/report/app.tsx b/packages/extension/src/view/report/app.tsx
new file mode 100644
index 000000000..70f595d90
--- /dev/null
+++ b/packages/extension/src/view/report/app.tsx
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { LibraryDetection } from '@ps-analysis-tool/library-detection';
+/**
+ * Internal dependencies
+ */
+import './app.css';
+import {
+ CookiesSection,
+ BlockedCookiesSection,
+ FramesSection,
+ ExemptedCookiesSection,
+} from './components';
+import { useData } from './stateProviders/data';
+
+const App = () => {
+ const data = useData(({ state }) => state.data);
+ return (
+
+
+
+ {data && data?.cookiesStatsComponents?.exempted?.length > 0 && (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default App;
diff --git a/packages/extension/src/view/report/components/blockedCookiesSection.tsx b/packages/extension/src/view/report/components/blockedCookiesSection.tsx
new file mode 100644
index 000000000..91df36cf7
--- /dev/null
+++ b/packages/extension/src/view/report/components/blockedCookiesSection.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ CookiesLandingWrapper,
+ CookiesMatrix,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useData } from '../stateProviders/data';
+
+const CookiesSection = () => {
+ const data = useData(({ state }) => state.data);
+
+ if (!data) {
+ return <>>;
+ }
+
+ return (
+
+ {data.cookiesStatsComponents.blockedCookiesLegend.length > 0 && (
+
+ )}
+
+ );
+};
+
+export default CookiesSection;
diff --git a/packages/extension/src/view/report/components/cookiesSection.tsx b/packages/extension/src/view/report/components/cookiesSection.tsx
new file mode 100644
index 000000000..80f927c1b
--- /dev/null
+++ b/packages/extension/src/view/report/components/cookiesSection.tsx
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ CookiesLandingWrapper,
+ CookiesMatrix,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useData } from '../stateProviders/data';
+
+const CookiesSection = () => {
+ const data = useData(({ state }) => state.data);
+
+ if (!data) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+};
+
+export default CookiesSection;
diff --git a/packages/extension/src/view/report/components/exemptedCookiesSection.tsx b/packages/extension/src/view/report/components/exemptedCookiesSection.tsx
new file mode 100644
index 000000000..e40c77d55
--- /dev/null
+++ b/packages/extension/src/view/report/components/exemptedCookiesSection.tsx
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ CookiesLandingWrapper,
+ CookiesMatrix,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useData } from '../stateProviders/data';
+
+const ExemptedCookiesSection = () => {
+ const data = useData(({ state }) => state.data);
+
+ if (!data) {
+ return <>>;
+ }
+
+ return (
+
+ {data.cookiesStatsComponents.exemptedCookiesLegend.length > 0 && (
+
+ )}
+
+ );
+};
+export default ExemptedCookiesSection;
diff --git a/packages/extension/src/view/report/components/framesSection.tsx b/packages/extension/src/view/report/components/framesSection.tsx
new file mode 100644
index 000000000..8982b11b5
--- /dev/null
+++ b/packages/extension/src/view/report/components/framesSection.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import {
+ CookiesLandingWrapper,
+ LEGEND_DESCRIPTION,
+ MatrixContainer,
+} from '@ps-analysis-tool/design-system';
+/**
+ * Internal dependencies
+ */
+import { useData } from '../stateProviders/data';
+
+const CookiesSection = () => {
+ const data = useData(({ state }) => state.data);
+
+ if (!data) {
+ return null;
+ }
+
+ const _data = data.frameStateCreator.legend.map((component) => {
+ const legendDescription = LEGEND_DESCRIPTION[component.label] || '';
+ return {
+ ...component,
+ description: legendDescription,
+ title: component.label,
+ containerClasses: '',
+ };
+ });
+
+ return (
+
+
+
+ );
+};
+
+export default CookiesSection;
diff --git a/packages/extension/src/view/report/components/index.ts b/packages/extension/src/view/report/components/index.ts
new file mode 100644
index 000000000..518994651
--- /dev/null
+++ b/packages/extension/src/view/report/components/index.ts
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { default as CookiesSection } from './cookiesSection';
+export { default as BlockedCookiesSection } from './blockedCookiesSection';
+export { default as ExemptedCookiesSection } from './exemptedCookiesSection';
+export { default as FramesSection } from './framesSection';
diff --git a/packages/extension/src/view/report/index.html b/packages/extension/src/view/report/index.html
new file mode 100644
index 000000000..4da392046
--- /dev/null
+++ b/packages/extension/src/view/report/index.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+ Report
+
+
+
+
+
diff --git a/packages/extension/src/view/report/index.tsx b/packages/extension/src/view/report/index.tsx
new file mode 100644
index 000000000..9503dd2dd
--- /dev/null
+++ b/packages/extension/src/view/report/index.tsx
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+import { LibraryDetectionProvider } from '@ps-analysis-tool/library-detection';
+import { noop } from '@ps-analysis-tool/common';
+
+/**
+ * Internal dependencies
+ */
+import App from './app';
+import { DataProvider } from './stateProviders/data';
+
+//@ts-ignore this global mock is needed for the provider LibraryDetectionProvider and the component LibraryDetection to work
+chrome = {
+ tabs: {
+ onUpdated: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ },
+ devtools: {
+ inspectedWindow: {
+ onResourceAdded: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ getResources: noop,
+ },
+ },
+ webNavigation: {
+ onErrorOccurred: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ onBeforeNavigate: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ onCompleted: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ },
+};
+
+document.addEventListener('DOMContentLoaded', () => {
+ const root = document.getElementById('root');
+
+ if (root) {
+ createRoot(root).render(
+
+
+
+
+
+ );
+ }
+});
diff --git a/packages/extension/src/view/report/stateProviders/data/context.ts b/packages/extension/src/view/report/stateProviders/data/context.ts
new file mode 100644
index 000000000..ae7369aee
--- /dev/null
+++ b/packages/extension/src/view/report/stateProviders/data/context.ts
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import {
+ createContext,
+ type CookieStatsComponents,
+ type FrameStateCreator,
+ type TabCookies,
+ type TabFrames,
+ type DataMapping,
+ type LibraryData,
+} from '@ps-analysis-tool/common';
+
+export interface DataStoreContext {
+ state: {
+ isDataLoaded: boolean;
+ data: {
+ cookieClassificationDataMapping: DataMapping[];
+ cookiesStatsComponents: CookieStatsComponents;
+ tabCookies: TabCookies;
+ tabFrames: TabFrames;
+ showInfoIcon: boolean;
+ showHorizontalMatrix: boolean;
+ blockedCookieDataMapping: DataMapping[];
+ showBlockedInfoIcon: boolean;
+ frameStateCreator: FrameStateCreator;
+ libraryMatches: LibraryData;
+ exemptedCookiesDataMapping: DataMapping[];
+ } | null;
+ };
+}
+
+const initialState: DataStoreContext = {
+ state: {
+ data: {
+ cookieClassificationDataMapping: [],
+ cookiesStatsComponents: {
+ legend: [],
+ blockedCookiesLegend: [],
+ firstParty: [],
+ thirdParty: [],
+ blocked: [],
+ exemptedCookiesLegend: [],
+ exempted: [],
+ },
+ tabCookies: {},
+ tabFrames: {},
+ showInfoIcon: false,
+ showHorizontalMatrix: false,
+ blockedCookieDataMapping: [],
+ showBlockedInfoIcon: false,
+ frameStateCreator: {
+ dataMapping: [],
+ legend: [],
+ },
+ libraryMatches: {},
+ exemptedCookiesDataMapping: [],
+ },
+ isDataLoaded: false,
+ },
+};
+
+export default createContext(initialState);
diff --git a/packages/extension/src/view/report/stateProviders/data/dataProvider.tsx b/packages/extension/src/view/report/stateProviders/data/dataProvider.tsx
new file mode 100644
index 000000000..ce193a1c1
--- /dev/null
+++ b/packages/extension/src/view/report/stateProviders/data/dataProvider.tsx
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React, { useEffect, useState, type PropsWithChildren } from 'react';
+import { useLibraryDetectionContext } from '@ps-analysis-tool/library-detection';
+/**
+ * Internal dependencies.
+ */
+import Context, { type DataStoreContext } from './context';
+
+const Provider = ({ children }: PropsWithChildren) => {
+ const [data, setData] = useState(null);
+ const [isDataLoaded, setIsDataLoaded] =
+ useState(false);
+
+ const { setLibraryMatches, setShowLoader } = useLibraryDetectionContext(
+ ({ actions }) => ({
+ setLibraryMatches: actions.setLibraryMatches,
+ setShowLoader: actions.setShowLoader,
+ })
+ );
+
+ useEffect(() => {
+ //@ts-ignore custom data attached to window breaks types
+ const _data = window.PSAT_DATA;
+
+ setData(_data);
+ setLibraryMatches(_data.libraryMatches);
+ setShowLoader(false);
+ setIsDataLoaded(true);
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default Provider;
diff --git a/packages/extension/src/view/report/stateProviders/data/index.ts b/packages/extension/src/view/report/stateProviders/data/index.ts
new file mode 100644
index 000000000..ba76d45b9
--- /dev/null
+++ b/packages/extension/src/view/report/stateProviders/data/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { default as DataProvider } from './dataProvider';
+export { default as SettingsContext } from './context';
+export { default as useData } from './useData';
diff --git a/packages/extension/src/view/report/stateProviders/data/useData.ts b/packages/extension/src/view/report/stateProviders/data/useData.ts
new file mode 100644
index 000000000..5967d72b0
--- /dev/null
+++ b/packages/extension/src/view/report/stateProviders/data/useData.ts
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies
+ */
+import { useContextSelector } from '@ps-analysis-tool/common';
+/**
+ * Internal dependencies.
+ */
+import Context, { type DataStoreContext } from './context';
+
+export function useData(): DataStoreContext;
+export function useData(selector: (state: DataStoreContext) => T): T;
+
+/**
+ * Data store hook.
+ * @param selector Selector function to partially select state.
+ * @returns selected part of the state
+ */
+export function useData(
+ selector: (state: DataStoreContext) => T | DataStoreContext = (state) => state
+) {
+ return useContextSelector(Context, selector);
+}
+
+export default useData;
diff --git a/packages/extension/src/view/report/tests/app.tsx b/packages/extension/src/view/report/tests/app.tsx
new file mode 100644
index 000000000..6c231de25
--- /dev/null
+++ b/packages/extension/src/view/report/tests/app.tsx
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import { noop } from '@ps-analysis-tool/common';
+import '@testing-library/jest-dom';
+
+/**
+ * Internal dependencies.
+ */
+import App from '../app';
+import data from './data.mock';
+import { useData } from '../stateProviders/data';
+
+jest.mock('../stateProviders/data', () => ({
+ useData: jest.fn(),
+}));
+const mockUseDataStore = useData as jest.Mock;
+
+describe('Report View', () => {
+ globalThis.chrome = {
+ tabs: {
+ //@ts-ignore
+ onUpdated: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ },
+ devtools: {
+ inspectedWindow: {
+ //@ts-ignore
+ onResourceAdded: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ getResources: noop,
+ },
+ },
+ webNavigation: {
+ //@ts-ignore
+ onErrorOccurred: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ //@ts-ignore
+ onBeforeNavigate: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ //@ts-ignore
+ onCompleted: {
+ addListener: noop,
+ removeListener: noop,
+ },
+ },
+ };
+
+ it('Should add chrome API mocks ', async () => {
+ mockUseDataStore.mockReturnValue(data);
+ render( );
+ expect(await screen.findByText('Total cookies')).toBeInTheDocument();
+ });
+});
diff --git a/packages/extension/src/view/report/tests/data.mock.ts b/packages/extension/src/view/report/tests/data.mock.ts
new file mode 100644
index 000000000..8362a35a8
--- /dev/null
+++ b/packages/extension/src/view/report/tests/data.mock.ts
@@ -0,0 +1,3946 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+const data = {
+ cookieClassificationDataMapping: [
+ {
+ title: 'Total cookies',
+ count: 28,
+ data: [
+ {
+ label: 'Functional',
+ count: 3,
+ color: '#5CC971',
+ countClassName: 'text-functional',
+ },
+ {
+ label: 'Marketing',
+ count: 5,
+ color: '#F3AE4E',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Analytics',
+ count: 12,
+ color: '#4C79F4',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Uncategorized',
+ count: 8,
+ color: '#EC7159',
+ countClassName: 'text-uncategorised',
+ },
+ ],
+ },
+ {
+ title: '1st party cookies',
+ count: 19,
+ data: [
+ {
+ count: 0,
+ color: '#5CC971',
+ },
+ {
+ count: 2,
+ color: '#F3AE4E',
+ },
+ {
+ count: 12,
+ color: '#4C79F4',
+ },
+ {
+ count: 5,
+ color: '#EC7159',
+ },
+ ],
+ },
+ {
+ title: '3rd party cookies',
+ count: 9,
+ data: [
+ {
+ count: 3,
+ color: '#5CC971',
+ },
+ {
+ count: 3,
+ color: '#F3AE4E',
+ },
+ {
+ count: 0,
+ color: '#4C79F4',
+ },
+ {
+ count: 3,
+ color: '#EC7159',
+ },
+ ],
+ },
+ ],
+ tabCookies: {
+ '_gcl_aurtcamp.com/': {
+ parsedCookie: {
+ name: '_gcl_au',
+ value: '1.1.1643004070.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2024-07-02T05:40:12.000Z',
+ partitionKey: '',
+ size: 32,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: 'Google',
+ category: 'Marketing',
+ name: '_gcl_au',
+ domain: '',
+ description:
+ 'Used by Google AdSense for experimenting with advertisement efficiency across websites using their services.',
+ retention: '3 months',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949254,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949269,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949274,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949295,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949301,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949307,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949311,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949316,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949320,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949719,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950078,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950096,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960181,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_user_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_user_id',
+ value: 'null',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 15,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_user_id',
+ domain: '.trustpilot.com',
+ description:
+ ' This cookie helps track visitor usage, events, target marketing, and can also measure application performance and stability.',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949255,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949269,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949274,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949295,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949301,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949307,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949311,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949316,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949320,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950078,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950096,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960181,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_group_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_group_id',
+ value: 'null',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 16,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_group_id',
+ domain: '.trustpilot.com',
+ description: 'Track visitor usage and events within the website',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949256,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949269,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949274,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949295,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949302,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949308,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949312,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949316,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949320,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950078,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950096,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960181,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'ajs_anonymous_idrtcamp.com/': {
+ parsedCookie: {
+ name: 'ajs_anonymous_id',
+ value: '%220eae481f-71ad-4118-9309-1f60ae8f9f6d%22',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T08:16:45.000Z',
+ partitionKey: '',
+ size: 58,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Trustpilot',
+ category: 'Analytics',
+ name: 'ajs_anonymous_id',
+ domain: '.trustpilot.com',
+ description:
+ 'Used for Analytics and help count how many people visit a certain site by tracking if you have visited before',
+ retention: '1 year',
+ dataController: 'Trustpilot',
+ gdprUrl: '',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949256,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949269,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949274,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949295,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949302,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949308,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949312,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949316,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949320,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950078,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950097,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960181,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_gartcamp.com/': {
+ parsedCookie: {
+ name: '_ga',
+ value: 'GA1.1.1593307359.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-13T13:12:29.716Z',
+ partitionKey: '',
+ size: 30,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: '_ga',
+ domain: 'google-analytics.com (3rd party) or',
+ description: 'ID used to identify users',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949256,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949269,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949274,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949295,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949302,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949308,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949312,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949317,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949321,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950079,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950097,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960182,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'FPIDrtcamp.com/': {
+ parsedCookie: {
+ name: 'FPID',
+ value:
+ 'FPID2.2.BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: '',
+ expires: '2025-05-13T13:12:31.895Z',
+ partitionKey: '',
+ size: 71,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: 'FPID',
+ domain: '',
+ description:
+ "Registers statistical data on users' behaviour on the website. Used for internal analytics by the website operator.",
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949257,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949270,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949274,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949296,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949302,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949308,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949312,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949317,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949321,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950079,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950097,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960182,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950364,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581950370,
+ },
+ ],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'FPAUrtcamp.com/': {
+ parsedCookie: {
+ name: 'FPAU',
+ value: '1.1.1643004070.1712122812',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: '',
+ expires: '2024-07-02T05:40:12.363Z',
+ partitionKey: '',
+ size: 29,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Marketing',
+ name: 'FPAU',
+ domain: '',
+ description:
+ 'Assigns a specific ID to the visitor. This allows the website to determine the number of specific user-visits for analysis and statistics.',
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949257,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949270,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949274,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949296,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949303,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949309,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949312,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949317,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949321,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950079,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950097,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960182,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950364,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581950370,
+ },
+ ],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'track_uidrtcamp.com/': {
+ parsedCookie: {
+ name: 'track_uid',
+ value: 'df985b92-a92b-7c79-35c7-3030565fd182',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-04-08T13:12:31.000Z',
+ partitionKey: '',
+ size: 45,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949259,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949270,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949272,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949275,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949297,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949303,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949309,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949313,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949318,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949321,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950079,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950097,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950157,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960183,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'stg_returning_visitorrtcamp.com/': {
+ parsedCookie: {
+ name: 'stg_returning_visitor',
+ value: 'Wed%2C%2003%20Apr%202024%2008:00:23%20GMT',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: 'strict',
+ expires: '2025-04-03T08:00:23.000Z',
+ partitionKey: '',
+ size: 62,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'Strict',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_returning_visitor',
+ domain: '',
+ description:
+ 'Determines if the visitor has already been to your website — they are returning visitors.',
+ retention: '365 days',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949260,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949270,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949273,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949275,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949297,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949303,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949309,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949313,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949318,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949321,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950079,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950096,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950158,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960183,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ 'FPLCrtcamp.com/': {
+ parsedCookie: {
+ name: 'FPLC',
+ value:
+ '5b%2FTP6HSsajlpXL%2B%2FZ2PpaY0zwdmiixUEsbGOx7OwPE%2B7wbuCk0KHjp8c7CySfrPf%2BNo9irtCirjzRBfW32pyNnIyfc%2BFGPClXEinxr2JOBE2cTh%2FxRiQo%2BpVwaqag%3D%3D',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: '',
+ expires: '2024-04-08T13:34:06.788Z',
+ partitionKey: '',
+ size: 152,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: 'FPLC',
+ domain: '',
+ description:
+ 'This FPLC cookie is the cross-domain linker cookie hashed from the FPID cookie. It’s not HttpOnly, which means it can be read with JavaScript. It has a relatively short lifetime, just 20 hours.',
+ retention: 'session',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949260,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949270,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949273,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949275,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949298,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949303,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949309,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949313,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949319,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949321,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950079,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950097,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950158,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960183,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_pk_id.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59rtcamp.com/': {
+ parsedCookie: {
+ name: '_pk_id.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59',
+ value: 'e232543d43714eb7.1712122813.8.1712581960.1712581950.',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: 'lax',
+ expires: '2025-05-06T13:12:40.000Z',
+ partitionKey: '',
+ size: 100,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'lax',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ },
+ analytics: {
+ platform: 'Matomo',
+ category: 'Analytics',
+ name: '_pk_id*',
+ domain: '',
+ description:
+ 'Used to store a few details about the user such as the unique visitor ID',
+ retention: '13 months',
+ dataController: 'Matomo',
+ gdprUrl: 'https://matomo.org/privacy-policy/',
+ wildcard: '1',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949260,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949270,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949273,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949275,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949298,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949304,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949310,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949314,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949319,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949321,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950079,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950096,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950158,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960186,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ '_parsely_visitorrtcamp.com/': {
+ parsedCookie: {
+ name: '_parsely_visitor',
+ value:
+ '{%22id%22:%22pid=55cc8d59-04cf-4bcd-aaca-5e6bb9ca7cc4%22%2C%22session_count%22:9%2C%22last_session_ts%22:1712581949558}',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-08T23:12:29.000Z',
+ partitionKey: '',
+ size: 135,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'request',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949262,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949271,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949273,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949275,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949298,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949304,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949310,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949314,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949319,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949322,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949721,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950080,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950098,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950158,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960184,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'stg_last_interactionrtcamp.com/': {
+ parsedCookie: {
+ name: 'stg_last_interaction',
+ value: 'Mon%2C%2008%20Apr%202024%2013:12:40%20GMT',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: 'strict',
+ expires: '2025-04-08T13:12:40.000Z',
+ partitionKey: false,
+ size: 61,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ sameSite: 'strict',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_last_interaction',
+ domain: '',
+ description:
+ "Determines whether the last visitor's session is still in progress or a new session has started.",
+ retention: '365 days',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949262,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949271,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949273,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949275,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949299,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949305,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949310,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949314,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949320,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949322,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950080,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950096,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950159,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960185,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ isBlocked: true,
+ blockedReasons: ['DomainMismatch'],
+ warningReasons: [],
+ },
+ '_ga_7HKDVLRRV4rtcamp.com/': {
+ parsedCookie: {
+ name: '_ga_7HKDVLRRV4',
+ value: 'GS1.1.1712581949.10.0.1712581956.0.0.1647693890',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2025-05-13T13:12:36.795Z',
+ partitionKey: '',
+ size: 61,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ partitioned: false,
+ sameSite: 'lax',
+ },
+ analytics: {
+ platform: 'Google Analytics',
+ category: 'Analytics',
+ name: '_ga_*',
+ domain: 'google-analytics.com (3rd party) or ',
+ description: 'ID used to identify users',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '1',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '73',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2020/11/site-logo-black.svg',
+ blocked: false,
+ timeStamp: 1712581949262,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '74',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Google.svg',
+ blocked: false,
+ timeStamp: 1712581949271,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '75',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/10/meta-logo2.svg',
+ blocked: false,
+ timeStamp: 1712581949273,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '76',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/09/Automattic.svg',
+ blocked: false,
+ timeStamp: 1712581949275,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '79',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/NewsUK.svg',
+ blocked: false,
+ timeStamp: 1712581949299,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '80',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/PMC.svg',
+ blocked: false,
+ timeStamp: 1712581949305,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '81',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2022/05/Aljazeera.svg',
+ blocked: false,
+ timeStamp: 1712581949310,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '82',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Award.svg',
+ blocked: false,
+ timeStamp: 1712581949314,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '83',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2021/03/google-logo-testimonials.svg',
+ blocked: false,
+ timeStamp: 1712581949320,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '85',
+ url: 'https://rtcamp.com/wp-content/uploads/sites/2/2023/09/Whats-new.svg',
+ blocked: false,
+ timeStamp: 1712581949322,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949721,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950080,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950098,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950158,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960185,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ '_parsely_sessionrtcamp.com/': {
+ parsedCookie: {
+ name: '_parsely_session',
+ value:
+ '{%22sid%22:9%2C%22surl%22:%22https://rtcamp.com/%22%2C%22sref%22:%22%22%2C%22sts%22:1712581949558%2C%22slts%22:1712567085259}',
+ domain: '.rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: '',
+ expires: '2024-04-08T13:42:29.000Z',
+ partitionKey: '',
+ size: 141,
+ priority: 'Medium',
+ httpOnly: false,
+ sameParty: false,
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'request',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581949720,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '109',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/css/jetpack.css?ver=13.2.2',
+ blocked: false,
+ timeStamp: 1712581950080,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950097,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950158,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960184,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: [],
+ },
+ 'warmly_b4dafe8509a5fd61b4850acb8a60c06bopps-api.getwarmly.com/api/sessions/trpc':
+ {
+ isBlocked: true,
+ parsedCookie: {
+ domain: 'opps-api.getwarmly.com',
+ expires: '2025-04-05T09:33:25.133Z',
+ httpOnly: true,
+ name: 'warmly_b4dafe8509a5fd61b4850acb8a60c06b',
+ path: '/api/sessions/trpc',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'None',
+ secure: true,
+ session: false,
+ size: 172,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ '%7B%22sessionId%22%3A%22c75eb9a9-9ae9-43b8-b3da-5ceabbf59d44%22%2C%22sessionUserId%22%3A%2210dd5156-c0b4-4b75-966d-bc1b66ab6263%22%7D',
+ samesite: 'none',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.124',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581949903,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['NotOnPath', 'DomainMismatch'],
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ },
+ 'stg_traffic_source_priorityrtcamp.com/': {
+ parsedCookie: {
+ name: 'stg_traffic_source_priority',
+ value: '1',
+ domain: 'rtcamp.com',
+ path: '/',
+ secure: false,
+ httponly: false,
+ samesite: 'strict',
+ expires: '2024-04-08T13:42:40.000Z',
+ partitionKey: false,
+ size: 28,
+ priority: 'Medium',
+ partitioned: false,
+ sameSite: 'strict',
+ },
+ analytics: {
+ platform: 'Piwik',
+ category: 'Analytics',
+ name: 'stg_traffic_source_priority',
+ domain: '',
+ description:
+ 'Stores the type of traffic source that explains how the visitor reached your website.',
+ retention: '30 minutes',
+ dataController: 'Piwik',
+ gdprUrl: 'https://piwik.pro/privacy-policy/',
+ wildcard: '0',
+ },
+ headerType: 'javascript',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '116',
+ url: 'https://rtcamp.com/wp-content/mu-plugins/jetpack-13.2/jetpack_vendor/automattic/jetpack-image-cdn/dist/image-cdn.js?minify=false&ver=132249e245926ae3e188',
+ blocked: false,
+ timeStamp: 1712581950159,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960185,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: true,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ },
+ 'NIDgoogle.com/': {
+ parsedCookie: {
+ name: 'NID',
+ value:
+ '513=fEZHdYbXcRMAOF3ZPEA3vRl9Dm7-B9JLfpLpTrtY3gDHBfo77B_V95BsxRPFvj7YXREgcHTvevfSVQwA7uWRBks6qoX0kKjqJ4I2zPwGXO436kL3thFCJu9nDXhnmGj6_Arpl_OQ8r50YccBg8N7qSxa2Dt_bhE7DnuyrRK91bv69GFnGAnpGEzA7pvdyPxB_WX9SQpPQ4U',
+ domain: '.google.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-10-07T21:20:50.696Z',
+ partitionKey: '',
+ size: 210,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'Google',
+ category: 'Marketing',
+ name: 'NID',
+ domain: 'google.com',
+ description:
+ 'This cookies is used to collect website statistics and track conversion rates and Google ad personalisation',
+ retention: '1 year',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://accounts.google.com/gsi/client?ver=1670238691',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '118',
+ url: 'https://accounts.google.com/gsi/client?ver=1670238691',
+ blocked: false,
+ timeStamp: 1712581950164,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.150',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950306,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '120',
+ url: 'https://analytics.google.com/g/s/collect?dma=0>m=45j91e4440v882644066z871645728z99177835882za200&_gsid=7HKDVLRRV4ncGMn9AhupAY-Kzz8UzrVw',
+ blocked: false,
+ timeStamp: 1712581950371,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.153',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950449,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '125',
+ url: 'https://accounts.google.com/gsi/style',
+ blocked: false,
+ timeStamp: 1712581950481,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '130',
+ url: 'https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ blocked: false,
+ timeStamp: 1712581950506,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.166',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950560,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '139',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=vmtgeiagaah9',
+ blocked: false,
+ timeStamp: 1712581950656,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '141',
+ url: 'https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ blocked: false,
+ timeStamp: 1712581950659,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.182',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950660,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '142',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=1gwdsmvwc4h5',
+ blocked: false,
+ timeStamp: 1712581950671,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '456D57955FFFE760F7C7CBB8DB0A6565',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950741,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1CBC1E18D4104CCB9A543F8821D77A52',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950742,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.196',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950744,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '149',
+ url: 'https://accounts.google.com/gsi/status?client_id=549796576131-8aoqmiheqf84a8bh3dl10ec2kp2v6e7p.apps.googleusercontent.com&as=2r0i4ezF5ZHWI2EE12JSdQ',
+ blocked: false,
+ timeStamp: 1712581950745,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '153',
+ url: 'https://www.google.com/js/bg/OMzbJ87gkB5MAUky6mmDB4mflkEza4rQHUJNCD4hS_4.js',
+ blocked: false,
+ timeStamp: 1712581950846,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '157',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712581950862,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '158',
+ url: 'https://www.google.com/js/bg/MAj5J5iEgh_vMgeickC5b2xvhmiD7VG83v9sx_9XVJI.js',
+ blocked: false,
+ timeStamp: 1712581950875,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '160',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712581950888,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '165',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712581951039,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1AC032028CF13BA78D4CE0F71FCCCDDA',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581951040,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '166',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712581951135,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '168',
+ url: 'https://www.google.com/js/bg/MAj5J5iEgh_vMgeickC5b2xvhmiD7VG83v9sx_9XVJI.js',
+ blocked: false,
+ timeStamp: 1712581951267,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.212',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581951787,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '177',
+ url: 'https://accounts.google.com/gsi/status?client_id=549796576131-8aoqmiheqf84a8bh3dl10ec2kp2v6e7p.apps.googleusercontent.com&as=2r0i4ezF5ZHWI2EE12JSdQ',
+ blocked: false,
+ timeStamp: 1712581951788,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.226',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581953413,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '191',
+ url: 'https://www.google.com/pagead/1p-user-list/11351157933/?random=1712581953245&cv=11&fst=1712581200000&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&fmt=3&is_vtc=1&cid=CAQSKQB7FLtq77Cr83eyZWMOh75-kFS-xT343ZEQweVwrt951p5KTOqKEXVS&random=266600465&rmt_tld=0&ipr=y',
+ blocked: false,
+ timeStamp: 1712581953414,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '325',
+ url: 'https://accounts.google.com/gsi/style',
+ blocked: false,
+ timeStamp: 1712581960195,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '332',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=1gwdsmvwc4h5',
+ blocked: false,
+ timeStamp: 1712581960197,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '345',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=vmtgeiagaah9',
+ blocked: false,
+ timeStamp: 1712581960312,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '346',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712581960315,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [13, 8, 9, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ '_GRECAPTCHAwww.google.com/recaptcha': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: 'www.google.com',
+ expires: '2024-10-05T13:12:31.240Z',
+ httpOnly: true,
+ name: '_GRECAPTCHA',
+ path: '/recaptcha',
+ priority: 'High',
+ sameParty: false,
+ sameSite: 'None',
+ secure: true,
+ session: false,
+ size: 100,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ '09ABIEJosgzZMW6tkpObHeXL81IlTnzBe2V5o-7fUsIXyxakYYBKH9Az_p8bdutmiWyL6bJX-vCoshIu0gxzGl-k8',
+ samesite: 'none',
+ partitionKey: '',
+ httponly: true,
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.150',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950306,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.153',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950448,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '130',
+ url: 'https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ blocked: false,
+ timeStamp: 1712581950506,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.166',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950560,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '139',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=vmtgeiagaah9',
+ blocked: false,
+ timeStamp: 1712581950656,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '141',
+ url: 'https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ blocked: false,
+ timeStamp: 1712581950659,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.182',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950660,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '142',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=1gwdsmvwc4h5',
+ blocked: false,
+ timeStamp: 1712581950671,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '456D57955FFFE760F7C7CBB8DB0A6565',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950741,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1CBC1E18D4104CCB9A543F8821D77A52',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950742,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.196',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950744,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '157',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712581950861,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '160',
+ url: 'https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-',
+ blocked: false,
+ timeStamp: 1712581950888,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '165',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712581951039,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1AC032028CF13BA78D4CE0F71FCCCDDA',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581951040,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '166',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712581951135,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.212',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581951786,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.226',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581953413,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '332',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&theme=light&size=invisible&badge=bottomright&cb=1gwdsmvwc4h5',
+ blocked: false,
+ timeStamp: 1712581960196,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '345',
+ url: 'https://www.google.com/recaptcha/api2/anchor?ar=1&k=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&co=aHR0cHM6Ly9ydGNhbXAuY29tOjQ0Mw..&hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&size=invisible&cb=vmtgeiagaah9',
+ blocked: false,
+ timeStamp: 1712581960310,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '346',
+ url: 'https://www.google.com/recaptcha/api2/bframe?hl=en&v=rz4DvU-cY2JYCwHSTck0_qm-&k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712581960312,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '166',
+ url: 'https://www.google.com/recaptcha/api2/reload?k=6Le6JpwaAAAAAFkASVap1OUThl-lQSJC0r9kLl2I',
+ blocked: false,
+ timeStamp: 1712581951242,
+ },
+ ],
+ },
+ blockedReasons: ['NotOnPath', 'DomainMismatch'],
+ analytics: {
+ platform: 'Google reCAPTCHA',
+ category: 'Functional',
+ name: '_GRECAPTCHA',
+ domain: 'google.com',
+ description:
+ 'Google reCAPTCHA sets a necessary cookie (_GRECAPTCHA) when executed for the purpose of providing its risk analysis.',
+ retention: '179 days',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [13, 8, 9, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_SOME_EVENTS',
+ },
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'SNIDgoogle.com/verify': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: '.google.com',
+ expires: '2024-10-05T06:36:29.696Z',
+ httpOnly: true,
+ name: 'SNID',
+ path: '/verify',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'Lax',
+ secure: true,
+ session: false,
+ size: 103,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value:
+ 'AOYECSr1AIksFOU_JTnc2ZZ-4TzCOICD8R03NsbLY3NmJpowc-xGVCb-BN4PM0erTr7W32PjsGaYrtD9kva2AlNWHsra2M4iwX8',
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.150',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950306,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.153',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950448,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.166',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950559,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950659,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '456D57955FFFE760F7C7CBB8DB0A6565',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950741,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1CBC1E18D4104CCB9A543F8821D77A52',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950742,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.196',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950744,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1AC032028CF13BA78D4CE0F71FCCCDDA',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581951039,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.212',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581951787,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.226',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581953413,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['NotOnPath', 'SameSiteLax'],
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ warningReasons: [],
+ },
+ 'AECgoogle.com/': {
+ isBlocked: true,
+ parsedCookie: {
+ domain: '.google.com',
+ expires: '2024-09-29T13:56:56.309Z',
+ httpOnly: true,
+ name: 'AEC',
+ path: '/',
+ priority: 'Medium',
+ sameParty: false,
+ sameSite: 'Lax',
+ secure: true,
+ session: false,
+ size: 61,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ value: 'AQTF6HyG1VGHI6o8fu3nQ-FoJdbMr-JjFktcDDgVZYiHk1wSKkdoi-oXoQ',
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.150',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950306,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.153',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950449,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.166',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950560,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.182',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950660,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '456D57955FFFE760F7C7CBB8DB0A6565',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950741,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1CBC1E18D4104CCB9A543F8821D77A52',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950742,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.196',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581950744,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '1AC032028CF13BA78D4CE0F71FCCCDDA',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581951040,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.212',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581951787,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.226',
+ url: '',
+ blocked: true,
+ timeStamp: 1712581953413,
+ },
+ ],
+ responseEvents: [],
+ },
+ blockedReasons: ['SameSiteLax'],
+ analytics: {
+ platform: 'Google Ads',
+ category: 'Functional',
+ name: 'AEC',
+ domain: 'google.com',
+ description:
+ 'AEC cookies ensure that requests within a browsing session are made by the user, and not by other sites. These cookies prevent malicious sites from acting on behalf of a user without that user’s knowledge.',
+ retention: '6 months',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ url: '',
+ headerType: 'request',
+ isFirstParty: false,
+ frameIdList: [],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ },
+ warningReasons: [],
+ },
+ 'FPGSIDrtcamp.com/': {
+ isBlocked: false,
+ blockedReasons: [],
+ parsedCookie: {
+ expires: '2024-04-08T13:42:30.363Z',
+ httponly: false,
+ secure: true,
+ path: '/',
+ domain: '.rtcamp.com',
+ samesite: 'strict',
+ name: 'FPGSID',
+ value: '1.1712581950.1712581950.G-7HKDVLRRV4.ncGMn9AhupAY-Kzz8UzrVw',
+ partitionKey: '',
+ size: 65,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960185,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '76817.127',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950367,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '106',
+ url: 'https://ggsutfx.rtcamp.com/g/collect?v=2&tid=G-7HKDVLRRV4>m=45je4430v882644066z871645728za200&_p=1712581949257&gcd=13l3l3l3l1&npa=0&dma=0&cid=1593307359.1712122812&ecid=1647693890&ul=en-us&sr=1440x900&ur=IN-KA&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&are=1&pae=1&pscdl=noapi&sst.uc=IN&sst.gse=1&sst.etld=google.co.in&sst.gcd=13l3l3l3l1&sst.tft=1712581949257&sst.ude=0&_s=1&sid=1712581949&sct=10&seg=0&dl=https%3A%2F%2Frtcamp.com%2F&dt=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&en=page_view&_ss=1&ep.content_group=Other&tfd=1668&richsstsse',
+ blocked: false,
+ timeStamp: 1712581950370,
+ },
+ ],
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: '',
+ isFirstParty: true,
+ headerType: 'request',
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ warningReasons: [],
+ },
+ 'ar_debugdoubleclick.net/': {
+ parsedCookie: {
+ name: 'ar_debug',
+ value: '1',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2024-05-05T06:17:14.801Z',
+ partitionKey: '',
+ size: 9,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'ar_debug',
+ domain: 'doubleclick.net',
+ description: 'Store and track conversions',
+ retention: 'Persistent',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4440v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '122',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4440v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712581950371,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.155',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950501,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '189',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712581953245&cv=11&fst=1712581953245&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712581953253,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '190',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712581953245&cv=11&fst=1712581953245&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712581953254,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.225',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581953335,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '7F249134584B2E5CB2A63A190D401895',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581953437,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '333',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712581953245&cv=11&fst=1712581953245&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712581960199,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [14, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'IDEdoubleclick.net/': {
+ parsedCookie: {
+ name: 'IDE',
+ value:
+ 'AHWqTUlOB-8ILGGuwKJVjURVYIWUPrakwD7qZ8dW3EuMsd1IjF147meBsb14R4DSSQc',
+ domain: '.doubleclick.net',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2025-05-13T06:44:32.161Z',
+ partitionKey: '',
+ size: 70,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: 'DoubleClick/Google Marketing',
+ category: 'Marketing',
+ name: 'IDE',
+ domain: 'doubleclick.net (3rd party)',
+ description:
+ 'This cookie is used for targeting, analyzing and optimisation of ad campaigns in DoubleClick/Google Marketing Suite',
+ retention: '2 years',
+ dataController: 'Google',
+ gdprUrl: 'https://privacy.google.com/take-control.html',
+ wildcard: '0',
+ },
+ headerType: 'request',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4440v882644066z871645728z99177835882za200&aip=1',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '122',
+ url: 'https://stats.g.doubleclick.net/g/collect?v=2&dma=0&tid=G-7HKDVLRRV4&cid=BbK4osGDATp%2FUJYvpHnCoBghznOOng6Zu9R3wuq9nb0%3D.1712122812>m=45j91e4440v882644066z871645728z99177835882za200&aip=1',
+ blocked: false,
+ timeStamp: 1712581950371,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.155',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950501,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '189',
+ url: 'https://googleads.g.doubleclick.net/pagead/viewthroughconversion/11351157933/?random=1712581953245&cv=11&fst=1712581953245&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1&rfmt=3&fmt=4',
+ blocked: false,
+ timeStamp: 1712581953253,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '190',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712581953245&cv=11&fst=1712581953245&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712581953254,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.225',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581953336,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '7F249134584B2E5CB2A63A190D401895',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581953438,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '333',
+ url: 'https://td.doubleclick.net/td/rul/11351157933?random=1712581953245&cv=11&fst=1712581953245&fmt=3&bg=ffffff&guid=ON&async=1>m=45be4430z871645728za201&gcd=13l3l3l3l1&dma=0&u_w=1440&u_h=900&url=https%3A%2F%2Frtcamp.com%2F&hn=www.googleadservices.com&frm=0&tiba=Robust%20Enterprise%20WordPress%20Solutions%20%7C%20rtCamp&value=-995&npa=0&pscdl=noapi&auid=1643004070.1712122812&uaa=arm&uab=64&uafvl=Google%2520Chrome%3B123.0.6312.107%7CNot%253AA-Brand%3B8.0.0.0%7CChromium%3B123.0.6312.107&uamb=0&uam=&uap=macOS&uapv=14.3.0&uaw=0&fledge=1&data=event%3Dtest%3Bgoogle_business_vertical%3Dcustom%3Bid%3Dtest1',
+ blocked: false,
+ timeStamp: 1712581960199,
+ },
+ ],
+ responseEvents: [],
+ },
+ isFirstParty: false,
+ frameIdList: [14, 0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'JSESSIONIDads.kwanzoo.com/': {
+ blockedReasons: [
+ 'SameSiteUnspecifiedTreatedAsLax',
+ 'ExcludeSameSiteUnspecifiedTreatedAsLax',
+ ],
+ warningReasons: ['WarnSameSiteUnspecifiedCrossSiteContext'],
+ isBlocked: true,
+ parsedCookie: {
+ name: 'JSESSIONID',
+ value: '1E68CDE89606D58E7043FF00C62D08E6',
+ domain: 'ads.kwanzoo.com',
+ path: '/',
+ secure: true,
+ httponly: false,
+ samesite: '',
+ expires: 0,
+ partitionKey: '',
+ size: 42,
+ priority: 'Medium',
+ },
+ analytics: {
+ platform: 'J2EE',
+ category: 'Functional',
+ name: 'JSESSIONID*',
+ domain: '',
+ description:
+ 'JSESSIONID is a cookie generated by Servlet containers and used for session management in J2EE web applications for HTTP protocol. If a Web server is using a cookie for session management, it creates and sends JSESSIONID cookie to the client and then the client sends it back to the server in subsequent HTTP requests. JSESSIONID is a platform session cookie and is used by sites with JavaServer Pages (JSP). The cookie is used to maintain an anonymous user session by the server.',
+ retention: 'session',
+ dataController: 'J2EE',
+ gdprUrl: '',
+ wildcard: '1',
+ },
+ url: 'https://ads.kwanzoo.com/embed-code/12716',
+ networkEvents: {
+ requestEvents: [],
+ responseEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '102',
+ url: 'https://ads.kwanzoo.com/embed-code/12716',
+ blocked: true,
+ timeStamp: 1712581950421,
+ },
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: 'D579C7C73FAFF5D1DAF4D13CADFA3FD2',
+ url: 'https://ads.kwanzoo.com/widget/inactive/12716',
+ blocked: true,
+ timeStamp: 1712581951517,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '123',
+ url: 'https://ads.kwanzoo.com/widget/inactive/12716',
+ blocked: true,
+ timeStamp: 1712581951519,
+ },
+ ],
+ },
+ headerType: 'response',
+ isFirstParty: false,
+ frameIdList: [7, 0],
+ blockingStatus: {
+ inboundBlock: 'BLOCKED_IN_ALL_EVENTS',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ 'tuida.usbrowserspeed.com/': {
+ parsedCookie: {
+ name: 'tuid',
+ value: '1eadd2b3-4c04-4400-906c-71d58120510a',
+ domain: 'a.usbrowserspeed.com',
+ path: '/',
+ secure: true,
+ httponly: true,
+ samesite: 'none',
+ expires: '2025-04-08T13:12:31.242Z',
+ partitionKey: '',
+ size: 40,
+ priority: 'Medium',
+ httpOnly: true,
+ sameParty: false,
+ sameSite: 'None',
+ session: false,
+ sourcePort: 443,
+ sourceScheme: 'Secure',
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ headerType: 'response',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '124',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ blocked: false,
+ timeStamp: 1712581950422,
+ },
+ {
+ type: 'CDP_REQUEST_WILL_BE_SENT_EXTRA_INFO',
+ requestId: '76817.156',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581950953,
+ },
+ ],
+ responseEvents: [
+ {
+ type: 'CDP_RESPONSE_RECEIVED_EXTRA_INFO',
+ requestId: '76817.156',
+ url: '',
+ blocked: false,
+ timeStamp: 1712581951239,
+ },
+ {
+ type: 'CHROME_WEBREQUEST_ON_RESPONSE_STARTED',
+ requestId: '124',
+ url: 'https://a.usbrowserspeed.com/metrics.js?pid=b92811d1223bc439179cdad26908fb731d6efd5a5e78bcec5d89bb4590870e06',
+ blocked: false,
+ timeStamp: 1712581951242,
+ },
+ ],
+ },
+ isFirstParty: false,
+ frameIdList: [0],
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ isBlocked: false,
+ blockedReasons: [],
+ warningReasons: ['WarnThirdPartyPhaseout'],
+ },
+ 'cookietestrtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: 'Session',
+ name: 'cookietest',
+ partitioned: false,
+ path: '/',
+ sameSite: 'lax',
+ secure: false,
+ value: '1',
+ partitionKey: false,
+ size: 11,
+ priority: 'Medium',
+ },
+ networkEvents: {
+ requestEvents: [],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: '',
+ category: 'Uncategorized',
+ name: '',
+ domain: '',
+ description: '',
+ retention: '',
+ dataController: '',
+ gdprUrl: '',
+ wildcard: '',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ '_pk_ses.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59rtcamp.com/': {
+ parsedCookie: {
+ domain: 'rtcamp.com',
+ expires: '2024-04-08T13:42:40.000Z',
+ name: '_pk_ses.10c7acc6-abb4-44cd-82dc-44190bf2463d.de59',
+ partitioned: false,
+ path: '/',
+ sameSite: 'lax',
+ secure: true,
+ value: '*',
+ partitionKey: '',
+ size: 50,
+ priority: 'Medium',
+ httponly: false,
+ samesite: 'lax',
+ },
+ networkEvents: {
+ requestEvents: [
+ {
+ type: 'CHROME_WEBREQUEST_ON_BEFORE_SEND_HEADERS',
+ requestId: '318',
+ url: 'https://rtcamp.com/',
+ blocked: false,
+ timeStamp: 1712581960185,
+ },
+ ],
+ responseEvents: [],
+ },
+ analytics: {
+ platform: 'Matomo',
+ category: 'Analytics',
+ name: '_pk_ses*',
+ domain: '',
+ description:
+ 'Short lived cookies used to temporarily store data for the visit',
+ retention: '30 minutes',
+ dataController: 'Matomo',
+ gdprUrl: 'https://matomo.org/privacy-policy/',
+ wildcard: '1',
+ },
+ url: 'https://rtcamp.com/',
+ headerType: 'javascript',
+ frameIdList: [0],
+ blockedReasons: [],
+ warningReasons: [],
+ isBlocked: false,
+ isFirstParty: true,
+ blockingStatus: {
+ inboundBlock: 'NOT_BLOCKED',
+ outboundBlock: 'NOT_BLOCKED',
+ },
+ },
+ },
+ cookiesStatsComponents: {
+ legend: [
+ {
+ label: 'Functional',
+ count: 3,
+ color: '#5CC971',
+ countClassName: 'text-functional',
+ },
+ {
+ label: 'Marketing',
+ count: 5,
+ color: '#F3AE4E',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Analytics',
+ count: 12,
+ color: '#4C79F4',
+ countClassName: 'text-uncategorised',
+ },
+ {
+ label: 'Uncategorized',
+ count: 8,
+ color: '#EC7159',
+ countClassName: 'text-uncategorised',
+ },
+ ],
+ firstParty: [
+ {
+ count: 0,
+ color: '#5CC971',
+ },
+ {
+ count: 2,
+ color: '#F3AE4E',
+ },
+ {
+ count: 12,
+ color: '#4C79F4',
+ },
+ {
+ count: 5,
+ color: '#EC7159',
+ },
+ ],
+ thirdParty: [
+ {
+ count: 3,
+ color: '#5CC971',
+ },
+ {
+ count: 3,
+ color: '#F3AE4E',
+ },
+ {
+ count: 0,
+ color: '#4C79F4',
+ },
+ {
+ count: 3,
+ color: '#EC7159',
+ },
+ ],
+ blocked: [
+ {
+ count: 5,
+ color: '#7D8471',
+ },
+ {
+ count: 3,
+ color: '#79553D',
+ },
+ {
+ count: 2,
+ color: '#FFA420',
+ },
+ {
+ count: 1,
+ color: '#FF7514',
+ },
+ {
+ count: 1,
+ color: '#1C542D',
+ },
+ ],
+ blockedCookiesLegend: [
+ {
+ label: 'DomainMismatch',
+ count: 5,
+ color: '#7D8471',
+ countClassName: 'text-battle-dress',
+ },
+ {
+ label: 'NotOnPath',
+ count: 3,
+ color: '#79553D',
+ countClassName: 'text-brownstone',
+ },
+ {
+ label: 'SameSiteLax',
+ count: 2,
+ color: '#FFA420',
+ countClassName: 'text-honey-wax',
+ },
+ {
+ label: 'SameSiteUnspecifiedTreatedAsLax',
+ count: 1,
+ color: '#FF7514',
+ countClassName: 'text-sparks-in-green',
+ },
+ {
+ label: 'ExcludeSameSiteUnspecifiedTreatedAsLax',
+ count: 1,
+ color: '#1C542D',
+ countClassName: 'text-jay-bird',
+ },
+ ],
+ exempted: [
+ {
+ count: 3,
+ color: '#F9DC5C',
+ },
+ ],
+ exemptedCookiesLegend: [
+ {
+ label: 'UserSetting',
+ count: 3,
+ color: '#F9DC5C',
+ countClassName: 'text-napels-yellow',
+ },
+ ],
+ },
+ tabFrames: {
+ 'https://rtcamp.com': {
+ frameIds: [0],
+ frameType: 'outermost_frame',
+ isOnRWS: false,
+ },
+ 'https://ads.kwanzoo.com': {
+ frameIds: [7],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ 'https://www.google.com': {
+ frameIds: [8, 9, 13],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ 'https://td.doubleclick.net': {
+ frameIds: [14],
+ frameType: 'sub_frame',
+ isOnRWS: false,
+ },
+ },
+ showInfoIcon: true,
+ showHorizontalMatrix: false,
+ blockedCookieDataMapping: [
+ {
+ title: 'Blocked cookies',
+ count: 8,
+ data: [
+ {
+ count: 5,
+ color: '#7D8471',
+ },
+ {
+ count: 3,
+ color: '#79553D',
+ },
+ {
+ count: 2,
+ color: '#FFA420',
+ },
+ {
+ count: 1,
+ color: '#FF7514',
+ },
+ {
+ count: 1,
+ color: '#1C542D',
+ },
+ ],
+ },
+ ],
+ showBlockedInfoIcon: true,
+ frameStateCreator: {
+ dataMapping: [
+ {
+ title: 'Frames',
+ count: 4,
+ data: [
+ {
+ count: 4,
+ color: '#25ACAD',
+ },
+ {
+ count: 3,
+ color: '#F54021',
+ },
+ {
+ count: 3,
+ color: '#AF7AA3',
+ },
+ {
+ count: 4,
+ color: '#C5A06A',
+ },
+ {
+ count: 0,
+ color: '#A98307',
+ },
+ ],
+ },
+ ],
+ legend: [
+ {
+ label: 'Total frames',
+ count: 4,
+ color: '#25ACAD',
+ countClassName: 'text-greenland-green',
+ },
+ {
+ label: 'Frames with cookies',
+ count: 4,
+ color: '#C5A06A',
+ countClassName: 'text-good-life',
+ },
+ {
+ label: 'Frames with blocked cookies',
+ count: 3,
+ color: '#AF7AA3',
+ countClassName: 'text-victorian-violet',
+ },
+ {
+ label: 'Frames with unblocked cookies',
+ count: 3,
+ color: '#F54021',
+ countClassName: 'text-strawberry-spinach-red',
+ },
+ {
+ label: 'Fenced frames',
+ count: 0,
+ color: '#A98307',
+ countClassName: 'text-chestnut-gold',
+ },
+ ],
+ },
+ libraryMatches: {
+ gsiV2: {
+ signatureMatches: 0,
+ matches: [],
+ moduleMatch: 0,
+ },
+ gis: {
+ signatureMatches: 0,
+ matches: [],
+ },
+ 'fb-comments': {
+ domQuerymatches: [],
+ },
+ 'fb-likes': {
+ domQuerymatches: [],
+ },
+ 'disqus-comments': {
+ domQuerymatches: [],
+ },
+ 'jetpack-comments': {
+ domQuerymatches: [],
+ },
+ 'jetpack-likes': {
+ domQuerymatches: [],
+ },
+ reCaptcha: {
+ domQuerymatches: [
+ 'script[src]: https://www.google.com/recaptcha/api.js?render=6LevJpwaAAAAAF2HVImidaxUBSH3OkRiyxvxAQE8&ver=1.4.0',
+ 'script[src]: https://www.google.com/recaptcha/api.js?hl=en&ver=6.4.3#038;render=explicit',
+ ],
+ },
+ },
+ exemptedCookiesDataMapping: [
+ {
+ title: 'Exempted cookies',
+ count: 3,
+ data: [
+ {
+ count: 3,
+ color: '#F9DC5C',
+ },
+ ],
+ },
+ ],
+};
+
+export default data;
diff --git a/packages/extension/webpack.config.cjs b/packages/extension/webpack.config.cjs
index 6f954aed0..6450c314c 100644
--- a/packages/extension/webpack.config.cjs
+++ b/packages/extension/webpack.config.cjs
@@ -15,6 +15,7 @@
*/
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
+const HtmlInlineScriptPlugin = require('html-inline-script-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const WebpackBar = require('webpackbar');
const commonConfig = require('../../webpack.shared.cjs');
@@ -98,4 +99,28 @@ const popup = {
...commonConfig,
};
-module.exports = [root, devTools, popup];
+const report = {
+ entry: {
+ index: './src/view/report/index.tsx',
+ },
+ output: {
+ path: path.resolve(__dirname, '../../dist/extension/report'),
+ filename: '[name].js',
+ },
+ plugins: [
+ new WebpackBar({
+ name: 'Report',
+ color: '#357B66',
+ }),
+ new HtmlWebpackPlugin({
+ title: 'Report',
+ template: './src/view/report/index.html',
+ filename: 'index.html',
+ inject: true,
+ }),
+ new HtmlInlineScriptPlugin(),
+ ],
+ ...commonConfig,
+};
+
+module.exports = [root, devTools, popup, report];
diff --git a/packages/i18n/.eslintrc.json b/packages/i18n/.eslintrc.json
new file mode 100644
index 000000000..e7855d2dd
--- /dev/null
+++ b/packages/i18n/.eslintrc.json
@@ -0,0 +1,6 @@
+{
+ "rules": {
+ "no-console": "off"
+ },
+ "ignorePatterns": ["dist/**", "dist-types/**"]
+}
diff --git a/packages/i18n/README.md b/packages/i18n/README.md
new file mode 100644
index 000000000..98fd24fd4
--- /dev/null
+++ b/packages/i18n/README.md
@@ -0,0 +1,5 @@
+# i18n
+
+## Description
+
+A package that handles internationalization and localization.
diff --git a/packages/i18n/_locales/messages/en/messages.json b/packages/i18n/_locales/messages/en/messages.json
new file mode 100644
index 000000000..5b5087ad3
--- /dev/null
+++ b/packages/i18n/_locales/messages/en/messages.json
@@ -0,0 +1,16 @@
+{
+ "testString": {
+ "message": "Testing $details$ with $format$",
+ "description": "This is a test string",
+ "placeholders": {
+ "details": {
+ "content": "$2",
+ "example": "Details of the test"
+ },
+ "format": {
+ "content": "$1",
+ "example": "Format of the test"
+ }
+ }
+ }
+}
diff --git a/packages/i18n/_locales/packages/cli-dashboard/messages.json b/packages/i18n/_locales/packages/cli-dashboard/messages.json
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/i18n/_locales/packages/cli/messages.json b/packages/i18n/_locales/packages/cli/messages.json
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/i18n/_locales/packages/common/messages.json b/packages/i18n/_locales/packages/common/messages.json
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/i18n/_locales/packages/design-system/messages.json b/packages/i18n/_locales/packages/design-system/messages.json
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/i18n/_locales/packages/extension/messages.json b/packages/i18n/_locales/packages/extension/messages.json
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/i18n/package.json b/packages/i18n/package.json
new file mode 100644
index 000000000..3f0e2f809
--- /dev/null
+++ b/packages/i18n/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "@ps-analysis-tool/i18n",
+ "version": "0.7.0",
+ "description": "A package that handles internationalization and localization.",
+ "main": "./dist/index.js",
+ "types": "./dist-types/index.d.ts",
+ "source": "./src/index.ts",
+ "customExports": {
+ ".": {
+ "default": "./src/index.ts"
+ }
+ },
+ "scripts": {
+ "build": "tsc --build",
+ "dev": "tsc-watch --build"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/GoogleChromeLabs/ps-analysis-tool"
+ },
+ "author": "",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/GoogleChromeLabs/ps-analysis-tool/issues"
+ },
+ "homepage": "https://github.com/GoogleChromeLabs/ps-analysis-tool",
+ "dependencies": {
+ "intl-messageformat": "^10.5.11"
+ }
+}
diff --git a/packages/i18n/scripts/merge-messages.cjs b/packages/i18n/scripts/merge-messages.cjs
new file mode 100644
index 000000000..27cea166f
--- /dev/null
+++ b/packages/i18n/scripts/merge-messages.cjs
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+const fs = require('fs');
+
+const PACKAGES = [
+ 'cli',
+ 'cli-dashboard',
+ 'common',
+ 'design-system',
+ 'extension',
+];
+const COMMON_PATH = 'packages/i18n/_locales';
+const TARGET = `${COMMON_PATH}/messages/en/messages.json`;
+
+const main = () => {
+ fs.writeFileSync(TARGET, '{}');
+
+ const messages = {};
+
+ PACKAGES.forEach((pkg) => {
+ const path = `${COMMON_PATH}/packages/${pkg}/messages.json`;
+ const data = fs.readFileSync(path, 'utf8') || '{}';
+ const parsed = JSON.parse(data);
+
+ Object.entries(parsed).forEach(([key, value]) => {
+ if (messages[key]) {
+ throw new Error(
+ `Duplicate key: ${key}, found in ${pkg}. Please resolve this conflict before continuing.`
+ );
+ }
+
+ messages[key] = value;
+ });
+ });
+
+ fs.writeFileSync(TARGET, JSON.stringify(messages, null, 2));
+};
+
+main();
diff --git a/packages/i18n/src/i18n.ts b/packages/i18n/src/i18n.ts
new file mode 100644
index 000000000..5909b3238
--- /dev/null
+++ b/packages/i18n/src/i18n.ts
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * External dependencies.
+ */
+import { existsSync, readFileSync } from 'fs';
+import { IntlMessageFormat } from 'intl-messageformat';
+
+/**
+ * Class representing Internationalization (i18n) functionality.
+ */
+class I18n {
+ private messages: {
+ [key: string]: {
+ message: string;
+ description: string;
+ placeholders: {
+ [key: string]: {
+ content: string;
+ example: string;
+ };
+ };
+ };
+ } = {};
+
+ /**
+ * Initializes the messages object with the provided messages.
+ * @param {object} messages - The messages object containing translations.
+ */
+ initMessages(messages = {}) {
+ this.messages = messages;
+ }
+
+ /**
+ * Creates an array of possible locale strings based on the provided locale.
+ * @param {string} locale - The locale string.
+ * @returns {string[]} An array of locale strings.
+ */
+ private createLocaleArray(locale: string) {
+ return [locale, locale.split('-')[0], locale.split('_')[0], 'en'];
+ }
+
+ /**
+ * Asynchronously loads messages data for the dashboard.
+ * @param {string} locale - The locale string.
+ * @returns {Promise} A promise that resolves when messages are loaded.
+ */
+ async loadDashboardMessagesData(locale: string) {
+ const localeArray = this.createLocaleArray(locale);
+
+ let idx = 0;
+
+ const fetchWithRetry = async () => {
+ if (idx >= localeArray.length) {
+ return;
+ }
+
+ try {
+ const response = await fetch(
+ `/_locales/${localeArray[idx]}/messages.json`
+ );
+
+ if (!response.ok) {
+ throw new Error(
+ `Failed to fetch messages for locale ${localeArray[idx]}`
+ );
+ }
+
+ const data = await response.json();
+
+ this.initMessages(data);
+ } catch (error) {
+ idx++;
+ await fetchWithRetry();
+ }
+ };
+
+ await fetchWithRetry();
+ }
+
+ /**
+ * Loads messages data for the CLI.
+ * @param {string} locale - The locale string.
+ */
+ loadCLIMessagesData(locale: string) {
+ const localeArray = this.createLocaleArray(locale);
+
+ for (const _locale of localeArray) {
+ if (
+ existsSync(`packages/i18n/_locales/messages/${_locale}/messages.json`)
+ ) {
+ const messages = JSON.parse(
+ readFileSync(
+ `packages/i18n/_locales/messages/${_locale}/messages.json`,
+ {
+ encoding: 'utf-8',
+ }
+ )
+ );
+
+ this.initMessages(messages);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Retrieves a translated message for a given key.
+ * @param {string} key - The key of the message to retrieve.
+ * @param {string[]} [substitutions] - An array of substitution values for placeholders in the message.
+ * @param {boolean} [escapeLt] - Whether to escape '<' characters.
+ * @returns {string} The translated message.
+ */
+ getMessage(key: string, substitutions?: string[], escapeLt?: boolean) {
+ if (typeof chrome !== 'undefined' && chrome?.i18n?.getMessage) {
+ // @ts-ignore - Outdated definition.
+ return chrome.i18n.getMessage(key, substitutions, {
+ escapeLt: Boolean(escapeLt),
+ });
+ }
+
+ return this._parseMessage(key, substitutions, escapeLt);
+ }
+
+ /**
+ * Parses a message with substitutions and placeholders.
+ * @param {string} key - The key of the message to parse.
+ * @param {string[]} [substitutions] - An array of substitution values for placeholders in the message.
+ * @param {boolean} [escapeLt] - Whether to escape '<' characters.
+ * @returns {string} The parsed message.
+ */
+ private _parseMessage(
+ key: string,
+ substitutions?: string[],
+ escapeLt?: boolean
+ ) {
+ const messageObj = this.messages?.[key];
+
+ if (!messageObj) {
+ return '';
+ }
+
+ const message = messageObj.message
+ .split('$')
+ .map((part, idx) => (idx % 2 ? `{${part}}` : part))
+ .join('');
+
+ const placeholders = Object.entries(messageObj.placeholders || {}).reduce<{
+ [key: string]: string;
+ }>((acc, [placeholderKey, val]) => {
+ const idx = Number(val.content.substring(1)) - 1;
+
+ acc[placeholderKey] = substitutions?.[idx] || '';
+
+ return acc;
+ }, {});
+
+ return new IntlMessageFormat(message, 'en', undefined, {
+ ignoreTag: escapeLt,
+ }).format(placeholders) as string;
+ }
+}
+
+export default new I18n();
diff --git a/packages/i18n/src/index.ts b/packages/i18n/src/index.ts
new file mode 100644
index 000000000..6bacad137
--- /dev/null
+++ b/packages/i18n/src/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { default as I18n } from './i18n';
diff --git a/packages/i18n/src/tests/i18n.ts b/packages/i18n/src/tests/i18n.ts
new file mode 100644
index 000000000..733265c0f
--- /dev/null
+++ b/packages/i18n/src/tests/i18n.ts
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * External dependencies.
+ */
+import fs from 'fs';
+
+/**
+ * Internal dependencies.
+ */
+import I18n from '../i18n';
+
+describe('I18n', () => {
+ // mock fetch function
+ const fetchMock = jest.fn();
+
+ beforeAll(() => {
+ global.fetch = fetchMock;
+ });
+
+ afterAll(() => {
+ // @ts-ignore
+ global.fetch = undefined;
+ });
+
+ it('should load messages data for the dashboard', async () => {
+ const locale = 'en';
+ const messages = {
+ 'test.message': {
+ message: 'Test message for $name$',
+ description: 'Test message description',
+ placeholders: {
+ name: {
+ content: '$1',
+ example: 'John Doe',
+ },
+ },
+ },
+ };
+
+ fetchMock.mockResolvedValueOnce({
+ json: () => Promise.resolve(messages),
+ ok: true,
+ });
+
+ await I18n.loadDashboardMessagesData(locale);
+
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock).toHaveBeenCalledWith('/_locales/en/messages.json');
+
+ expect(I18n.getMessage('test.message', ['Sam'])).toEqual(
+ 'Test message for Sam'
+ );
+ });
+
+ it('should load CLI messages data', async () => {
+ const existsSyncMock = jest.spyOn(fs, 'existsSync');
+ const readFileSyncMock = jest.spyOn(fs, 'readFileSync');
+ const locale = 'hi';
+ const messages = {
+ 'test.message': {
+ message: 'Test message for $name$',
+ description: 'Test message description',
+ placeholders: {
+ name: {
+ content: '$1',
+ example: 'John Doe',
+ },
+ },
+ },
+ };
+
+ readFileSyncMock.mockReturnValueOnce(JSON.stringify(messages));
+ await I18n.loadCLIMessagesData(locale);
+
+ expect(existsSyncMock).toHaveBeenCalledWith(
+ 'packages/i18n/_locales/messages/hi/messages.json'
+ );
+ expect(existsSyncMock).toHaveBeenCalledTimes(4);
+
+ expect(readFileSyncMock).toHaveBeenCalledWith(
+ 'packages/i18n/_locales/messages/en/messages.json',
+ {
+ encoding: 'utf-8',
+ }
+ );
+ expect(readFileSyncMock).toHaveBeenCalledTimes(1);
+
+ expect(I18n.getMessage('test.message', ['Sam'])).toEqual(
+ 'Test message for Sam'
+ );
+ });
+});
diff --git a/packages/i18n/tsconfig.json b/packages/i18n/tsconfig.json
new file mode 100644
index 000000000..d2aea4c9e
--- /dev/null
+++ b/packages/i18n/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "jsx": "preserve",
+ "rootDir": "src",
+ "target": "es6",
+ "lib": ["es2021"],
+ "module": "commonjs",
+ "outDir": "dist",
+ "declarationDir": "dist-types",
+ "composite": true,
+ "strict": true,
+ "sourceMap": true,
+ "esModuleInterop": true,
+ "moduleResolution": "node"
+ },
+ "exclude": ["**/tests/**/*.ts", "dist/**", "dist-types/**"]
+}
diff --git a/packages/library-detection/package.json b/packages/library-detection/package.json
index aee8d7262..397500b0b 100644
--- a/packages/library-detection/package.json
+++ b/packages/library-detection/package.json
@@ -1,6 +1,6 @@
{
"name": "@ps-analysis-tool/library-detection",
- "version": "0.6.0",
+ "version": "0.7.0",
"description": "A package for detecting libraries for potential breakage",
"main": "./src/index.ts",
"source": "./src/index.ts",
diff --git a/packages/library-detection/src/components/libraryDetection/index.tsx b/packages/library-detection/src/components/libraryDetection/index.tsx
index 0ebc0e443..72855ae3b 100644
--- a/packages/library-detection/src/components/libraryDetection/index.tsx
+++ b/packages/library-detection/src/components/libraryDetection/index.tsx
@@ -18,7 +18,7 @@
*/
import React, { memo } from 'react';
import {
- CookiesLandingContainer,
+ CookiesLandingWrapper,
COLOR_MAP,
ProgressBar,
} from '@ps-analysis-tool/design-system';
@@ -94,7 +94,7 @@ const LibraryDetection = memo(function LibraryDetection() {
);
return (
-
+
);
});
diff --git a/packages/library-detection/src/core/stateProvider/index.tsx b/packages/library-detection/src/core/stateProvider/index.tsx
index 0141ac15f..cef91e36f 100644
--- a/packages/library-detection/src/core/stateProvider/index.tsx
+++ b/packages/library-detection/src/core/stateProvider/index.tsx
@@ -22,8 +22,11 @@ import React, {
useCallback,
useEffect,
} from 'react';
-import { createContext, useContextSelector } from 'use-context-selector';
-import { noop } from '@ps-analysis-tool/common';
+import {
+ noop,
+ useContextSelector,
+ createContext,
+} from '@ps-analysis-tool/common';
/**
* Internal dependencies.
@@ -123,8 +126,11 @@ export const LibraryDetectionProvider = ({ children }: PropsWithChildren) => {
);
const onNavigatedListener = useCallback(
- ({ frameId }: chrome.webNavigation.WebNavigationFramedCallbackDetails) => {
- if (frameId === 0) {
+ ({
+ frameId,
+ tabId: _tabId,
+ }: chrome.webNavigation.WebNavigationFramedCallbackDetails) => {
+ if (frameId === 0 && Number(tabId) === Number(_tabId)) {
setLibraryMatches(initialLibraryMatches);
setIsCurrentTabLoading(true);
setShowLoader(true);
@@ -132,7 +138,7 @@ export const LibraryDetectionProvider = ({ children }: PropsWithChildren) => {
setIsInitialDataUpdated(false);
}
},
- []
+ [tabId]
);
const onCompleted = useCallback(
diff --git a/packages/library-detection/src/types.ts b/packages/library-detection/src/types.ts
index c4ee8981b..3e47ed30e 100644
--- a/packages/library-detection/src/types.ts
+++ b/packages/library-detection/src/types.ts
@@ -46,7 +46,7 @@ export type ScriptTagUnderCheck = {
export type AccordionItem = {
count: number;
- isAffected: boolean;
+ hasIssues: boolean;
title: string;
superTitle: string;
superTitleDescription: string;
diff --git a/scripts/delete-build-artifacts.cjs b/scripts/delete-build-artifacts.cjs
index a8d529eb5..cbabd084b 100644
--- a/scripts/delete-build-artifacts.cjs
+++ b/scripts/delete-build-artifacts.cjs
@@ -17,7 +17,7 @@
const path = require('path');
const rimraf = require('rimraf');
-const dirs = ['common'];
+const dirs = ['common', 'i18n'];
dirs.forEach((dir) => {
const distDir = path.resolve(__dirname, `../packages/${dir}/dist`);
diff --git a/scripts/update-cookie-db.cjs b/scripts/update-cookie-db.cjs
index c261f144d..6223c55a9 100644
--- a/scripts/update-cookie-db.cjs
+++ b/scripts/update-cookie-db.cjs
@@ -81,6 +81,39 @@ const errorHandler = (err) => {
process.exit(1);
};
+/**
+ * Add keys to the locale file and replace the text with keys in the formattedData.
+ * @param formattedData formatted data
+ */
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const addKeysToLocale = async (formattedData) => {
+ const messagesPath = path.resolve(
+ 'packages/i18n/_locales/messages/en/messages.json'
+ );
+ const messages = await fs.readJson(messagesPath);
+
+ const regex = /[:/ *-.%“”()[\]]/g;
+
+ Object.entries(formattedData).forEach(([key, [value]]) => {
+ const descriptionKey = `OCD_${key.replace(regex, '_')}_description`;
+ messages[descriptionKey] = {
+ message: value.description,
+ description: 'Description of the cookie from the Open Cookie DB',
+ };
+ value.description = descriptionKey;
+
+ const retentionKey = `OCD_retention_${value.retention.replace(regex, '_')}`;
+ messages[retentionKey] = {
+ message: value.retention,
+ description: 'Retention period of the cookie from the Open Cookie DB',
+ };
+
+ value.retention = retentionKey;
+ });
+
+ await fs.writeJson(messagesPath, messages, { spaces: 2 });
+};
+
/**
* Download the csv file from the Open Cookie DB, format the data and write it to open-cookie-database.json.
*/
diff --git a/scripts/update-rws-json.cjs b/scripts/update-rws-json.cjs
index 046f7a554..6242a4b43 100644
--- a/scripts/update-rws-json.cjs
+++ b/scripts/update-rws-json.cjs
@@ -25,6 +25,30 @@ const errorHandler = (err) => {
process.exit(1);
};
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const addKeysToLocale = async (data) => {
+ const messagesPath = path.resolve(
+ 'packages/i18n/_locales/messages/en/messages.json'
+ );
+ const messages = await fs.readJson(messagesPath);
+
+ data.sets.forEach((set) => {
+ const rationalesObj = set.rationaleBySite;
+ Object.entries(rationalesObj).forEach(([site, rationale]) => {
+ const key = `RWS_rationale_${site.replace(/[:/ *-.%“”()[\]]/g, '_')}`;
+
+ messages[key] = {
+ message: rationale,
+ description: 'Rationale for a site in the related website set',
+ };
+
+ rationalesObj[site] = key;
+ });
+ });
+
+ await fs.writeJson(messagesPath, messages, { spaces: 2 });
+};
+
const main = async () => {
console.log('Updating related_website_sets.json file...'); // eslint-disable-line no-console
@@ -36,6 +60,7 @@ const main = async () => {
}
const data = await response.json();
+
await fs.writeFile(
path.resolve(targetDIR, 'related_website_sets.json'),
JSON.stringify(data, null, 2)
diff --git a/tailwind.config.cjs b/tailwind.config.cjs
index e32f0fd54..7836155cc 100644
--- a/tailwind.config.cjs
+++ b/tailwind.config.cjs
@@ -28,10 +28,13 @@ delete colors['blueGray'];
module.exports = {
darkMode: 'class',
content: [
- path.resolve(__dirname, './packages/extension/src/**/*.{tsx,js}'),
- path.resolve(__dirname, './packages/design-system/src/**/*.{tsx,js}'),
- path.resolve(__dirname, './packages/cli-dashboard/src/**/*.{tsx,js}'),
- path.resolve(__dirname, './packages/library-detection/src/**/*.{tsx,js}'),
+ path.resolve(__dirname, './packages/extension/src/**/*.{tsx,ts,js}'),
+ path.resolve(__dirname, './packages/design-system/src/**/*.{tsx,ts,js}'),
+ path.resolve(__dirname, './packages/cli-dashboard/src/**/*.{tsx,ts,js}'),
+ path.resolve(
+ __dirname,
+ './packages/library-detection/src/**/*.{tsx,ts,js}'
+ ),
],
theme: {
extend: {
@@ -140,6 +143,15 @@ module.exports = {
'jet-black': '#202142',
'warning-red': '#C33300',
'warning-orange': '#FE8d59',
+ charcoal: '#465362',
+ 'napels-yellow': '#F9DC5C',
+ 'red-corolla': '#ED254E',
+ moonstone: '#08A4BD',
+ 'noon-blue': '#446DF6',
+ 'chocolate-cosmos': '#4C212A',
+ 'cocoa-brown': '#D96C06',
+ 'persian-indigo': '#3A1772',
+ 'hollywood-cerise': '#D741A7',
},
backgroundColor: {
...colors,
@@ -189,6 +201,9 @@ module.exports = {
'leaf-green-dark': '#87DFB2',
'eerie-black': '#1F1F1F0F',
'light-yellow': '#FEFCE0',
+ 'bright-gray': '#E8EAED',
+ 'blue-berry': '#4582F4',
+ 'ultramarine-blue': '#3173EE',
'selection-green-light': '#117347',
'selection-green-dark': '#74d47e',
'selection-yellow-light': '#8b8f18',
diff --git a/tests/jest.config.cjs b/tests/jest.config.cjs
index 0d68abf5c..e51a9ba66 100644
--- a/tests/jest.config.cjs
+++ b/tests/jest.config.cjs
@@ -47,8 +47,12 @@ module.exports = {
'/data',
'/stories/',
'/packages/extension/src/view/devtools/index.tsx',
+ '/cli-dashboard/src/index.tsx',
'/packages/extension/src/view/popup/index.tsx',
'/packages/extension/src/view/devtools/devtools.ts',
+ '/packages/extension/src/utils/test-data',
+ '/packages/design-system/src/test-data',
+ '/packages/extension/src/contentScript/index.ts',
],
coverageReporters: ['lcov'],
collectCoverageFrom: [
diff --git a/webpack.shared.cjs b/webpack.shared.cjs
index 07608e35a..c2646ee19 100644
--- a/webpack.shared.cjs
+++ b/webpack.shared.cjs
@@ -26,6 +26,9 @@ module.exports = {
exclude: /node_modules/,
resolve: {
fullySpecified: false,
+ fallback: {
+ fs: false,
+ },
},
use: [
{