From c6739bbb766e54ca61cfaba7fbb7551aa2a13ec8 Mon Sep 17 00:00:00 2001 From: peterbarnett03 Date: Tue, 22 Oct 2024 14:17:46 -0400 Subject: [PATCH] chore: add Heap analytics (#6951) * chore: add Heap analytics * feat: unload analytics script on fail, use id appropriate to environment * fix: correct capitalization of heapanalyticsid --------- Co-authored-by: Peter Barnett Co-authored-by: Bill OConnell --- src/App.tsx | 17 ++++- src/utils/{vwo.ts => analyticsTools.ts} | 95 ++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 6 deletions(-) rename src/utils/{vwo.ts => analyticsTools.ts} (55%) diff --git a/src/App.tsx b/src/App.tsx index 12870e1e25..f515d0e99a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -38,7 +38,7 @@ import {AppState} from 'src/types' // Utils import {isFlagEnabled} from 'src/shared/utils/featureFlag' import {CLOUD} from 'src/shared/constants' -import {executeVWO} from 'src/utils/vwo' +import {executeVWO, executeHeap, unloadHeap} from 'src/utils/analyticsTools' // Providers import {UserAccountProvider} from 'src/accounts/context/userAccount' @@ -57,14 +57,14 @@ const App: FC = () => { if (CLOUD && isFlagEnabled('rudderstackReporting')) { try { load(RUDDERSTACK_WRITE_KEY, RUDDERSTACK_DATA_PLANE_URL) - } catch (error) { + } catch (err) { console.error( 'Error loading Rudderstack with wk: ', RUDDERSTACK_WRITE_KEY, ' at: ', RUDDERSTACK_DATA_PLANE_URL ) - reportErrorThroughHoneyBadger(error, { + reportErrorThroughHoneyBadger(err, { name: 'Rudderstack Loading Function', }) } @@ -104,6 +104,17 @@ const App: FC = () => { } } + if (CLOUD && isFlagEnabled('heapAnalytics')) { + try { + executeHeap() + } catch (err) { + unloadHeap() + reportErrorThroughHoneyBadger(err, { + name: 'Unable to load Heap Analytics', + }) + } + } + setAutoFreeze(false) }, []) diff --git a/src/utils/vwo.ts b/src/utils/analyticsTools.ts similarity index 55% rename from src/utils/vwo.ts rename to src/utils/analyticsTools.ts index 6862953df0..57b5567976 100644 --- a/src/utils/vwo.ts +++ b/src/utils/analyticsTools.ts @@ -1,8 +1,14 @@ -// this code is related to implementing the A/B testing tool VMO: https://vwo.com/ -// Whenever this script is updated, ensure that any changes are reflected in the -// error handling in App.tsx, especially for any elements that change opacity of the page. /* eslint-disable */ // @ts-nocheck + +import {getFlagValue} from 'src/shared/utils/featureFlag' + +/* This file is exclusively for third-party analytics tools used by the Cloud2 UI. */ + +/* This code implements the A/B testing tool VWO: https://vwo.com/ + The copy is largely copy-pasted from VWO instructions and is not maintained by InfluxData. + Whenever this script is updated, ensure that any changes are reflected in the + error handling in App.tsx, especially for any elements that change opacity of the page. */ export const executeVWO = () => { window._vwo_code = window._vwo_code || @@ -116,3 +122,86 @@ export const executeVWO = () => { return code })() } + +const HEAP_API_SCRIPT_SRC = 'heap-api.com' + +/* + The JS code in this function is copied from the installation instructions + at https://developers.heap.io/docs/web and is not maintained by InfluxData. + + Semicolons have been added to avoid ASI issues because this script uses IIFEs. + // Example: https://circleci.com/blog/ci-cd-for-js-iifes/ +*/ +export const executeHeap = () => { + // Retrieve the heap analytics id appropriate to the environment from ConfigCat. + const heapId = getFlagValue('heapanalyticsid') + if (!heapId) { + return + } + + // This block is imported from Heap. + ;(window.heapReadyCb = window.heapReadyCb || []), + (window.heap = window.heap || []), + (heap.load = function (e, t) { + ;(window.heap.envId = e), + (window.heap.clientConfig = t = t || {}), + (window.heap.clientConfig.shouldFetchServerConfig = !1) + var a = document.createElement('script') + ;(a.type = 'text/javascript'), + (a.async = !0), + (a.src = 'https://cdn.us.heap-api.com/config/' + e + '/heap_config.js') + var r = document.getElementsByTagName('script')[0] + r.parentNode.insertBefore(a, r) + var n = [ + 'init', + 'startTracking', + 'stopTracking', + 'track', + 'resetIdentity', + 'identify', + 'getSessionId', + 'getUserId', + 'getIdentity', + 'addUserProperties', + 'addEventProperties', + 'removeEventProperty', + 'clearEventProperties', + 'addAccountProperties', + 'addAdapter', + 'addTransformer', + 'addTransformerFn', + 'onReady', + 'addPageviewProperties', + 'removePageviewProperty', + 'clearPageviewProperties', + 'trackPageview', + ], + i = function (e) { + return function () { + var t = Array.prototype.slice.call(arguments, 0) + window.heapReadyCb.push({ + name: e, + fn: function () { + heap[e] && heap[e].apply(heap, t) + }, + }) + } + } + for (var p = 0; p < n.length; p++) heap[n[p]] = i(n[p]) + }) + + heap.load(heapId.toString()) +} + +// This unloads all artifacts from the Heap script if an error is encountered. +export const unloadHeap = () => { + delete window.heap + delete window.heapReadyCb + + const scripts = document.getElementsByTagName('script') + for (let s of scripts) { + if (s.src.includes(HEAP_API_SCRIPT_SRC)) { + s.remove() + } + } +}