Skip to content

Commit e21ea61

Browse files
fix: add missing tracking events (#435)
* fix: add missing tracking events - Includes adding new tracking events for subtab navigation. * test: add analytics mocks
1 parent ad1ab36 commit e21ea61

File tree

9 files changed

+70
-9
lines changed

9 files changed

+70
-9
lines changed

packages/toolbar/src/core/tests/new-design/FilterButton.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ vi.mock('motion/react', () => ({
1818
AnimatePresence: ({ children }: { children: React.ReactNode }) => <>{children}</>,
1919
}));
2020

21+
// Mock analytics
22+
vi.mock('../../ui/Toolbar/context/telemetry/AnalyticsProvider', () => ({
23+
useAnalytics: vi.fn().mockReturnValue({
24+
trackFilterChange: vi.fn(),
25+
}),
26+
}));
27+
2128
describe('FilterButton', () => {
2229
const AllProviders = ({ children }: { children: React.ReactNode }) => (
2330
<ActiveSubtabProvider>

packages/toolbar/src/core/tests/new-design/IconBar.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ vi.mock('../../ui/Toolbar/components/new/Tooltip', () => ({
2525
),
2626
}));
2727

28+
// Mock analytics
29+
vi.mock('../../ui/Toolbar/context/telemetry/AnalyticsProvider', () => ({
30+
useAnalytics: vi.fn().mockReturnValue({
31+
trackTabChange: vi.fn(),
32+
}),
33+
}));
34+
2835
describe('IconBar', () => {
2936
const defaultProps = {
3037
defaultActiveTab: 'flags' as const,

packages/toolbar/src/core/tests/new-design/TabBar.test.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ vi.mock('../../ui/Toolbar/components/new/ContentActions', () => ({
1111
ContentActions: () => <div data-testid="content-actions">Content Actions</div>,
1212
}));
1313

14+
// Mock analytics
15+
vi.mock('../../ui/Toolbar/context/telemetry/AnalyticsProvider', () => ({
16+
useAnalytics: vi.fn().mockReturnValue({
17+
trackSubtabChange: vi.fn(),
18+
}),
19+
}));
20+
1421
// Test wrapper that sets an active tab
1522
const TestWrapperWithTab = ({ tab }: { tab: 'flags' | 'monitoring' | 'settings' | 'interactive' }) => {
1623
const { setActiveTab } = useActiveTabContext();

packages/toolbar/src/core/ui/Toolbar/components/new/ContentActions.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
usePlugins,
77
useToolbarState,
88
useFlagsContext,
9+
useAnalytics,
910
} from '../../context';
1011
import { useActiveSubtabContext, useTabSearchContext } from './context';
1112
import { useContextsContext } from '../../context/api/ContextsProvider';
@@ -26,6 +27,7 @@ export function ContentActions() {
2627
const { events } = useEvents(eventInterceptionPlugin, searchTerm);
2728
const { setSearchTerm } = useTabSearchContext();
2829
const [searchIsExpanded, setSearchIsExpanded] = useState(false);
30+
const analytics = useAnalytics();
2931

3032
// Update search expansion when subtab changes
3133
// Expand if the new subtab has a search term, collapse if it doesn't
@@ -63,12 +65,14 @@ export function ContentActions() {
6365
const handleClearEvents = useCallback(() => {
6466
if (eventInterceptionPlugin) {
6567
eventInterceptionPlugin.clearEvents();
68+
analytics.trackClearEvents();
6669
}
67-
}, [eventInterceptionPlugin]);
70+
}, [eventInterceptionPlugin, analytics]);
6871

6972
const handleSync = useCallback(() => {
7073
refresh();
71-
}, [refresh]);
74+
analytics.trackRefresh();
75+
}, [refresh, analytics]);
7276

7377
const handleRefreshFlags = useCallback(() => {
7478
refreshFlags();
@@ -78,8 +82,9 @@ export function ContentActions() {
7882
(input: string) => {
7983
if (!activeSubtab) return;
8084
setSearchTerm(activeSubtab as SubTab, input);
85+
analytics.trackSearch(input);
8186
},
82-
[activeSubtab, setSearchTerm],
87+
[activeSubtab, setSearchTerm, analytics],
8388
);
8489

8590
return (

packages/toolbar/src/core/ui/Toolbar/components/new/FeatureFlags/FlagList.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
usePlugins,
1010
useToolbarState,
1111
useStarredFlags,
12+
useAnalytics,
1213
} from '../../../context';
1314
import { useTabSearchContext, useSubtabFilters } from '../context';
1415
import { FlagItem } from './FlagItem';
@@ -25,6 +26,7 @@ function DevServerFlagList() {
2526
const searchTerm = useMemo(() => searchTerms['flags'] || '', [searchTerms]);
2627
const { activeFilters } = useSubtabFilters('flags');
2728
const { isStarred } = useStarredFlags();
29+
const analytics = useAnalytics();
2830

2931
const scrollContainerRef = useRef<HTMLDivElement>(null);
3032
const getScrollElement = useCallback(() => scrollContainerRef.current, []);
@@ -96,15 +98,17 @@ function DevServerFlagList() {
9698
const handleOverride = useCallback(
9799
async (flagKey: string, value: any) => {
98100
await setOverride(flagKey, value);
101+
analytics.trackFlagOverride(flagKey, value, 'set');
99102
},
100-
[setOverride],
103+
[setOverride, analytics],
101104
);
102105

103106
const handleClearOverride = useCallback(
104107
async (flagKey: string) => {
105108
await clearOverride(flagKey);
109+
analytics.trackFlagOverride(flagKey, null, 'remove');
106110
},
107-
[clearOverride],
111+
[clearOverride, analytics],
108112
);
109113

110114
// Calculate stats
@@ -190,6 +194,7 @@ function SdkFlagList() {
190194
const searchTerm = useMemo(() => searchTerms['flags'] || '', [searchTerms]);
191195
const { activeFilters } = useSubtabFilters('flags');
192196
const { isStarred } = useStarredFlags();
197+
const analytics = useAnalytics();
193198

194199
const scrollContainerRef = useRef<HTMLDivElement>(null);
195200
const getScrollElement = useCallback(() => scrollContainerRef.current, []);
@@ -248,15 +253,17 @@ function SdkFlagList() {
248253
const handleOverride = useCallback(
249254
(flagKey: string, value: any) => {
250255
setOverride(flagKey, value);
256+
analytics.trackFlagOverride(flagKey, value, 'set');
251257
},
252-
[setOverride],
258+
[setOverride, analytics],
253259
);
254260

255261
const handleClearOverride = useCallback(
256262
(flagKey: string) => {
257263
removeOverride(flagKey);
264+
analytics.trackFlagOverride(flagKey, null, 'remove');
258265
},
259-
[removeOverride],
266+
[removeOverride, analytics],
260267
);
261268

262269
const handleHeightChange = useCallback(

packages/toolbar/src/core/ui/Toolbar/components/new/FilterOverlay/FilterOverlay.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useActiveSubtabContext } from '../context/ActiveSubtabProvider';
66
import { SubTab } from '../types';
77
import { IconButton } from '../../../../Buttons/IconButton';
88
import { CheckIcon, FilterTuneIcon } from '../../icons';
9+
import { useAnalytics } from '../../../context';
910
import * as styles from './FilterOverlay.module.css';
1011

1112
interface FilterOptionItemProps {
@@ -42,16 +43,19 @@ interface FilterOverlayContentProps {
4243
const FilterOverlayContent = memo(function FilterOverlayContent({ subtab, onClose }: FilterOverlayContentProps) {
4344
const overlayRef = useRef<HTMLDivElement>(null);
4445
const { getActiveFilters, getFilterConfig, toggleFilter, resetFilters, hasActiveNonDefaultFilters } = useFilters();
46+
const analytics = useAnalytics();
4547

4648
const config = getFilterConfig(subtab);
4749
const activeFilters = getActiveFilters(subtab);
4850
const hasNonDefaultFilters = hasActiveNonDefaultFilters(subtab);
4951

5052
const handleToggle = useCallback(
5153
(optionId: string) => {
54+
const wasActive = activeFilters.has(optionId);
5255
toggleFilter(subtab, optionId);
56+
analytics.trackFilterChange(optionId as 'all' | 'overrides' | 'starred', wasActive ? 'deselected' : 'selected');
5357
},
54-
[subtab, toggleFilter],
58+
[subtab, toggleFilter, activeFilters, analytics],
5559
);
5660

5761
const handleReset = useCallback(() => {

packages/toolbar/src/core/ui/Toolbar/components/new/IconBar/IconBar.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { FlaskIcon } from '../../icons/FlaskIcon';
88
import { Tooltip } from '../Tooltip';
99
import * as styles from './IconBar.module.css';
1010
import { enableInteractiveIcon, enableAiIcon, enableOptimizeIcon } from '../../../../../../flags/toolbarFlags';
11-
import { useActiveTabContext, useElementSelection } from '../../../context';
11+
import { useActiveTabContext, useElementSelection, useAnalytics } from '../../../context';
1212
import { TabId } from '../../../types/toolbar';
1313

1414
type Icon = {
@@ -29,6 +29,7 @@ export function IconBar({ defaultActiveTab }: IconBarProps) {
2929
const optimizeIconEnabled = enableOptimizeIcon();
3030
const { activeTab, setActiveTab } = useActiveTabContext();
3131
const { startSelection } = useElementSelection();
32+
const analytics = useAnalytics();
3233
const [hoveredIcon, setHoveredIcon] = useState<TabId | null>(null);
3334

3435
useEffect(() => {
@@ -74,10 +75,15 @@ export function IconBar({ defaultActiveTab }: IconBarProps) {
7475
startSelection();
7576
} else {
7677
// Switch to interactive mode AND start selection
78+
analytics.trackTabChange(activeTab || null, id);
7779
setActiveTab(id);
7880
startSelection();
7981
}
8082
} else {
83+
// Only track if actually changing tabs
84+
if (activeTab !== id) {
85+
analytics.trackTabChange(activeTab || null, id);
86+
}
8187
setActiveTab(id);
8288
}
8389
};

packages/toolbar/src/core/ui/Toolbar/components/new/SubtabDropdown.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useState, useRef, useEffect } from 'react';
22
import { AnimatePresence, motion } from 'motion/react';
33
import { ChevronDownIcon } from '../icons/ChevronDownIcon';
44
import { SubTab, TabConfig } from './types';
5+
import { useAnalytics } from '../../context';
56
import * as styles from './SubtabDropdown.module.css.ts';
67

78
interface SubtabDropdownProps {
@@ -13,6 +14,7 @@ interface SubtabDropdownProps {
1314
export function SubtabDropdown({ subtabs, activeSubtab, onSelectSubtab }: SubtabDropdownProps) {
1415
const [isOpen, setIsOpen] = useState(false);
1516
const dropdownRef = useRef<HTMLDivElement>(null);
17+
const analytics = useAnalytics();
1618

1719
const activeTab = subtabs.find((tab) => tab.id === activeSubtab);
1820
const activeLabel = activeTab?.label || 'Select';
@@ -33,6 +35,11 @@ export function SubtabDropdown({ subtabs, activeSubtab, onSelectSubtab }: Subtab
3335

3436
const handleSelect = (event: React.MouseEvent, subtab: SubTab) => {
3537
event.stopPropagation();
38+
39+
if (activeSubtab !== subtab) {
40+
analytics.trackSubtabChange(activeSubtab || null, subtab);
41+
}
42+
3643
onSelectSubtab(subtab);
3744
setIsOpen(false);
3845
};

packages/toolbar/src/core/utils/analytics.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const EVENTS = {
1010
POSITION_CHANGED: 'position.changed',
1111
AUTO_COLLAPSE_TOGGLED: 'auto.collapse.toggled',
1212
TAB_CHANGED: 'tab.changed',
13+
SUBTAB_CHANGED: 'subtab.changed',
1314
SEARCH: 'search',
1415
TOGGLE: 'toggle',
1516
TOGGLE_FLAG: 'toggle.flag',
@@ -116,6 +117,16 @@ export class ToolbarAnalytics {
116117
});
117118
}
118119

120+
/**
121+
* Track toolbar subtab navigation
122+
*/
123+
trackSubtabChange(fromSubtab: string | null, toSubtab: string): void {
124+
this.track(EVENTS.SUBTAB_CHANGED, {
125+
fromSubtab,
126+
toSubtab,
127+
});
128+
}
129+
119130
/**
120131
* Track search usage
121132
*/

0 commit comments

Comments
 (0)