diff --git a/background.js b/background.js index ac84ba7..8b37654 100755 --- a/background.js +++ b/background.js @@ -8,11 +8,10 @@ chrome.extension.* */ chrome.extension.onConnect.addListener(function (port) { - - var extensionListener = (message, sender, sendResponse) => { - console.info('Message:', message, sender, sendResponse); - }; + var extensionListener = (message, sender, sendResponse) => { + console.info("Message:", message, sender, sendResponse); + }; - // Listens to messages sent from the panel - chrome.extension.onMessage.addListener(extensionListener); -}); \ No newline at end of file + // Listens to messages sent from the panel + chrome.extension.onMessage.addListener(extensionListener); +}); diff --git a/devtools.html b/devtools.html index a088ad4..cf92362 100755 --- a/devtools.html +++ b/devtools.html @@ -1 +1,5 @@ - + + + + + diff --git a/manifest.json b/manifest.json index 8e47082..c3f4102 100755 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "Mixpanel Tools", - "version": "0.9", + "version": "1.0.0", "description": "A debugger tool helps to intercept mixpanel events and display event properties", "short_name": "mixpanel tools", "icons": { @@ -10,10 +10,15 @@ }, "devtools_page": "devtools.html", "background": { - "scripts": [ + "servicewroker": [ "background.js" ] }, - "permissions": [], - "manifest_version": 2 + "permissions": [ + "storage" + ], + "manifest_version": 3, + "action": { + "default_popup": "popup.html" + } } \ No newline at end of file diff --git a/panel.html b/panel.html index f922c24..101165b 100755 --- a/panel.html +++ b/panel.html @@ -1,80 +1,122 @@ + + + + - - - - - - - + +
+
+
+
+
+

Events

+
+
+

Properties

+
+
+
+
+
+
+
+ + + + + + + + +
propertyvalue
+ + +
+
- - - - - - +
+ - - - - - - - - - + + - \ No newline at end of file + + + + + + + + diff --git a/popup.html b/popup.html new file mode 100644 index 0000000..cebfcc5 --- /dev/null +++ b/popup.html @@ -0,0 +1,41 @@ + + + + Mixpanel tools + + + + +

Mixpanel tools

+

+ A debugger tool helps to intercept mixpanel events and display event + properties +

+ +
+
+ List of API hosts configured before, +
+ +
+ + + + diff --git a/popup.js b/popup.js new file mode 100644 index 0000000..7ca0ed5 --- /dev/null +++ b/popup.js @@ -0,0 +1,27 @@ +async function createList() { + const { SAVED_URL_KEY } = await chrome.storage.sync.get("SAVED_URL_KEY"); + const { SAVED_URL_KEY_LIST = [] } = await chrome.storage.sync.get( + "SAVED_URL_KEY_LIST" + ); + const saveURLs = new Set(SAVED_URL_KEY_LIST); + if (!saveURLs.has(SAVED_URL_KEY)) { + saveURLs.add(SAVED_URL_KEY); + } + + const mainList = document.getElementById("prev-url-list"); + const header = document.getElementById("header-list"); + + if (saveURLs.size > 0) { + header.style.display = "block"; + for (const savedURL of saveURLs) { + const li = document.createElement("li"); + li.textContent = savedURL; + mainList.appendChild(li); + } + await chrome.storage.sync.set({ SAVED_URL_KEY_LIST: Array.from(saveURLs) }); + } +} + +createList().catch((error) => { + console.error(error); +}); diff --git a/src/index.css b/src/index.css index cffda2c..798cf2a 100644 --- a/src/index.css +++ b/src/index.css @@ -10,7 +10,7 @@ body { background-color: #fff; } -#scroll-up-btn { +.scroll-btn { display: none; position: fixed; bottom: 20px; @@ -25,14 +25,14 @@ body { border-radius: 50%; color: #4183c4; transition: all 0.3s ease-in; - background-color: transparent; + background-color: #ffffff61; } -#scroll-up-btn:hover { +.scroll-btn:hover { color: #ea3511; } -#scroll-up-btn svg { +.scroll-btn svg { height: 50px; width: 50px; position: absolute; @@ -41,13 +41,6 @@ body { transform: translate(-50%, -50%) rotate(90deg); } -.ui.main.fluid.container { - margin-top: 4em; - border: 1px solid rgba(34, 36, 38, 0.15); - width: calc(100% - 10px); - padding: 0; -} - .ui.menu .item img.logo { margin-right: 1.5em; } @@ -64,12 +57,12 @@ body { } .item.active { - background: rgba(65, 131, 196, 0.24); - color: #444; + background: rgb(0, 123, 245); + color: #fff; } .item:hover { - background: rgba(65, 131, 196, 0.8); - color: #eee; + background: rgb(61, 158, 255); + color: #fff; } .ui.menu .item:hover { @@ -80,7 +73,7 @@ body { background: transparent !important; } -.ui.menu .item.batched-request{ +.ui.menu .item.batched-request { visibility: hidden; font-weight: 500; } @@ -98,19 +91,15 @@ body { content: "."; } -.ui.internally.celled.grid { - min-height: 50vh; -} - -.ui.celled.grid > .row > .six.wide.column.event-column { +#event-column { padding: 0; } -.ui.celled.grid > .row > .ten.wide.column.details-column { +#details-column { padding: 0; } -.event-column h3, -.details-column h3 { +#event-column h3, +#details-column h3 { margin: 0; padding: 0.5rem 0; text-align: center; @@ -119,20 +108,16 @@ body { } #event-list { - margin: 0.1rem 0; -} - -#property-table { - border: none !important; - margin: 0.1rem 0; + margin: 0; + padding: 0.2em 0; } -.table { +table.table { display: none; } table.active { - display: block; + display: table; } table td span { @@ -154,7 +139,7 @@ table td span { } /* keyframes */ -@-webkit-keyframes led { +@keyframes led { from { opacity: 0.2; } @@ -164,12 +149,43 @@ table td span { } } -@keyframes led { - from { - opacity: 0.2; - } +input#custom-api-host-input:not([value=""]) { + color: green; + border-color: rgba(34, 36, 38, 1); +} - to { - opacity: 1; - } +#main-container { + margin-top: 0; + width: calc(100% - 10px); + padding: 4em 10px 1em 10px; + height: 100vh; + overflow: hidden; +} + +#main-container-grid { + height: 100%; +} + +#main-container-wrapper { + height: 100%; + overflow: hidden; + border:1px solid #d4d4d5 +} + +#event-column { + height: 100%; + overflow: auto; +} + +#main-container-grid { + height: 100%; +} + +#details-row { + height: calc(100% - 56px); +} + +#details-column { + height: 100%; + overflow: auto; } diff --git a/src/index.js b/src/index.js index 9dfb0b6..9c8cb13 100644 --- a/src/index.js +++ b/src/index.js @@ -7,14 +7,14 @@ * * @classname MixpanelTool */ -class MixpanelTool { - constructor() { +class MixpanelTool { + constructor(customAPIHost) { this.state = { requests: {}, selectedRequest: {}, count: 0, - customAPIHost: "", + customAPIHost: customAPIHost || "", omitMixpanelProperty: true, record: true, }; @@ -62,16 +62,30 @@ class MixpanelTool { .off("input") .on("input", (event) => { let value = event && event.target ? event.target.value : ""; - this.customAPIHost = value.trim().toLowerCase(); + const customAPIHost = value.trim().toLowerCase(); + this.customAPIHost = customAPIHost; + saveCustomHost(customAPIHost); }); - $("#scroll-up-btn") + $("#custom-api-host-input").val(this.state.customAPIHost || ""); + + $("#details-scroll-up-btn") .off("click") .on("click", () => { - this.scrollToTop(); + this.detailsScrollToTop(); + }); + + $("#details-column") + .off("scroll") + .on("scroll", (e) => { + const isScrollable = e.target.clientHeight < e.target.scrollHeight; + console.log(e, isScrollable, e.target.scrollTop); + if (isScrollable && e.target.scrollTop > 500) { + $("#details-scroll-up-btn").show(); + } else { + $("#details-scroll-up-btn").hide(); + } }); - // register scroll - this.manageScrollToTop(); }); } @@ -113,7 +127,7 @@ class MixpanelTool { encodedData = urlParams.data || ""; properties = this.getProperties(encodedData); mixpanelRequest = Object.assign({}, urlParams, { - data: properties + data: properties, }); this.addRequest(mixpanelRequest); } @@ -153,11 +167,16 @@ class MixpanelTool { isRequestValid(requestObject) { if (requestObject && requestObject.request && requestObject.request.url) { - let isMixpanelURL = this.mixpanelAPIPattern.test(requestObject.request.url); + let isMixpanelURL = this.mixpanelAPIPattern.test( + requestObject.request.url + ); let customAPIHost = this.customAPIHost; if (isMixpanelURL) { return true; - } else if (customAPIHost && requestObject.request.url.includes(customAPIHost)) { + } else if ( + customAPIHost && + requestObject.request.url.includes(customAPIHost) + ) { return true; } } @@ -175,7 +194,8 @@ class MixpanelTool { (properties, newProperty) => { properties[newProperty.name] = newProperty.value; return properties; - }, {} + }, + {} ); } else { return {}; @@ -203,13 +223,14 @@ class MixpanelTool { Ref: https://github.com/mixpanel/mixpanel-js/releases/tag/v2.43.0 Mixpanel has changed the payload ecoding format, by default JSON string will be passed, unless api_payload_format:true is specified. - */ - base64regex = /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; - + */ + base64regex = + /^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/; + getProperties(dataParam) { let dataStr = decodeURIComponent(dataParam); // if Base64 - if(this.base64regex.test(dataStr)) { + if (this.base64regex.test(dataStr)) { dataStr = atob(dataStr); } return JSON.parse(dataStr); @@ -292,39 +313,77 @@ class MixpanelTool { }); } - scrollToTop() { - window.scrollTo({ - top: 0, - left: 0, - behavior: "smooth", - }); + detailsScrollToTop() { + $("#details-column").animate( + { + scrollTop: 0, + }, + 1000 + ); } manageScrollToTop() { // When the user scrolls down 20px from the top of the document, show the button - window.onscroll = function () { - scrollFunction(); - }; - - function scrollFunction() { - if ( - document.body.scrollTop > 50 || - document.documentElement.scrollTop > 50 - ) { - $("#scroll-up-btn").show(); - } else { - $("#scroll-up-btn").hide(); - } + const detailsColumn = document.querySelector("#details-column"); + if (detailsColumn && detailsColumn.onscroll) { + detailsColumn.onscroll = () => { + console.log("onscroll"); + if (detailsColumn.scrollTop > 50) { + $("#details-scroll-up-btn").show(); + } else { + $("#details-scroll-up-btn").hide(); + } + }; } } } +getSavedCustomHost = async () => { + try { + const result = await chrome.storage.sync.get("SAVED_URL_KEY"); + const value = result.SAVED_URL_KEY; + if (!value || typeof value !== "string") { + throw Error("value undefined"); + } + return value; + } catch (e) { + console.error("getSavedCustomHost", e); + return ""; + } +}; + +const saveCustomHost = async (customHost) => { + try { + await chrome.storage.sync.set({ SAVED_URL_KEY: customHost }); + return true; + } catch (e) { + console.error("saveCustomHost", e); + return false; + } +}; + // ready function for jQuery -$(function () { - // create mixpanel tool instance - const mixpanelTool = new MixpanelTool(); - //subscribe to network requests and detect mixpanel events - devToolsNetworkListner((request) => - mixpanelTool.handleMixpanelRequest(request) - ); +$(() => { + getSavedCustomHost().then((customHost) => { + // create mixpanel tool instance + const mixpanelTool = new MixpanelTool(customHost); + //subscribe to network requests and detect mixpanel events + devToolsNetworkListner((request) => + mixpanelTool.handleMixpanelRequest(request) + ); + }); }); + +// test data-generator +function generateTestData(mixpanelToolInstance) { + for (let i = 1; i < 50; i++) { + let properties = {}; + for (let j = 1; j < 500; j++) { + properties["test-property-" + j] = + i + Array[100].fill("new - data").join(" ") + j; + } + mixpanelToolInstance.addRequest({ + data: { properties, event: "event-" + i }, + }); + } +} diff --git a/src/utils/devtool.util.js b/src/utils/devtool.util.js index ce7a6a9..56b7e39 100644 --- a/src/utils/devtool.util.js +++ b/src/utils/devtool.util.js @@ -13,3 +13,4 @@ function devToolsNetworkListner(callbackFn) { } } } +