Skip to content

Commit 7bf8e5a

Browse files
benceruleanluchristian-byrneclaude
authored
feat(telemetry): add tracking for sidebar, run menu, dialogs, subgraphs, settings and credits (#6511)
Summary - Add comprehensive telemetry for key UI interactions using existing telemetry hooks (cloud-enabled, no-op in OSS): Sidebar and top-level - Node library button: `node_library` - Model library button: `model_library` - Workflows button: `workflows` - Assets/Media button: `assets` - Templates button: `templates` - Keyboard Shortcuts: `keyboard_shortcuts` - Console: `console` - Help Center: `help_center` - Settings (from Comfy logo menu): `settings_menu` Floating canvas menu - Minimap toggle: `minimap_toggle` - Hide links toggle: `hide_links` Run button and queue - Run button handle (drag): `run_button_handle` - Run mode selection: `run_instant`, `run_on_change` - Queue multiple: `queue_multiple` fires on each run when batch count > 1 (moved from batch-count-change to run-time, per guidance) Error dialogs - Close (X/mask/ESC): `error_dialog_close` via dialog onClose - Show report: `error_show_report` - Help fix this: `error_help_fix_this` - Find issues: `error_find_issues` Nodes / Subgraphs - Selection toolbox “Node info”: `node_info` - Enter subgraph (node header enter): `open_subgraph` - Subgraph breadcrumb navigation: `subgraph_breadcrumb_item` and `subgraph_breadcrumb_root` Settings / Credits / Search - Settings menu button (under Comfy logo): `settings_menu` - Purchase credits (Settings > Credits panel): tracked via existing `trackAddApiCreditButtonClicked` - Purchase credits (Avatar popover Top Up): tracked via existing `trackAddApiCreditButtonClicked` - Debounced search telemetry already present for node search and template filters; left as-is Notes and answers - Error dialog onClose: only fires when the dialog actually closes (X, mask, ESC, or programmatic close). “Show report” and “Help fix this” do not close the dialog; they each emit their own events. - Telemetry is behind the cloud provider; calls are optional (`useTelemetry()?.…`). OSS builds send nothing. Open questions / follow-ups - Primary Run button click: today cloud-only `trackRunButton` exists; we can also emit a UI-level `run` click (`UI_BUTTON_CLICKED` style) alongside it if desired. Confirm preference and I can add it. - Subgraph usage richness: if we want structured analytics (e.g., action, depth, subgraph id, node count), I can add a dedicated provider method and include richer metadata at enter/breadcrumb. - Optional parity: track the Comfy menu’s “Browse Templates” item in addition to the sidebar Templates button. Quality - Ran `pnpm lint:fix` and `pnpm typecheck`; both pass locally. Implementation details - All handlers refactored to named functions where needed; used `void` for intentionally unawaited async calls per lint rules. - Event names kept consistent in `button_id` strings; happy to align to a different naming scheme if you prefer. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6511-feat-telemetry-add-tracking-for-sidebar-run-menu-dialogs-subgraphs-settings-and-cre-29e6d73d365081a1b8b4fdfbbf40e18b) by [Unito](https://www.unito.io) --------- Co-authored-by: Christian Byrne <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent 31e405a commit 7bf8e5a

File tree

19 files changed

+210
-11
lines changed

19 files changed

+210
-11
lines changed

src/components/actionbar/ComfyActionbar.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { computed, nextTick, onMounted, ref, watch } from 'vue'
4848
4949
import { t } from '@/i18n'
5050
import { useSettingStore } from '@/platform/settings/settingStore'
51+
import { useTelemetry } from '@/platform/telemetry'
5152
import { cn } from '@/utils/tailwindUtil'
5253
5354
import ComfyRunButton from './ComfyRunButton'
@@ -132,6 +133,15 @@ watch(visible, async (newVisible) => {
132133
}
133134
})
134135
136+
/**
137+
* Track run button handle drag start using mousedown on the drag handle.
138+
*/
139+
useEventListener(dragHandleRef, 'mousedown', () => {
140+
useTelemetry()?.trackUiButtonClicked({
141+
button_id: 'actionbar_run_handle_drag_start'
142+
})
143+
})
144+
135145
const lastDragState = ref({
136146
x: x.value,
137147
y: y.value,

src/components/actionbar/ComfyRunButton/ComfyQueueButton.vue

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ import BatchCountEdit from '../BatchCountEdit.vue'
100100
101101
const workspaceStore = useWorkspaceStore()
102102
const queueCountStore = storeToRefs(useQueuePendingTaskCountStore())
103-
const { mode: queueMode } = storeToRefs(useQueueSettingsStore())
103+
const { mode: queueMode, batchCount } = storeToRefs(useQueueSettingsStore())
104104
105105
const { t } = useI18n()
106106
const queueModeMenuItemLookup = computed(() => {
@@ -118,6 +118,9 @@ const queueModeMenuItemLookup = computed(() => {
118118
label: `${t('menu.run')} (${t('menu.onChange')})`,
119119
tooltip: t('menu.onChangeTooltip'),
120120
command: () => {
121+
useTelemetry()?.trackUiButtonClicked({
122+
button_id: 'queue_mode_option_run_on_change_selected'
123+
})
121124
queueMode.value = 'change'
122125
}
123126
}
@@ -128,6 +131,9 @@ const queueModeMenuItemLookup = computed(() => {
128131
label: `${t('menu.run')} (${t('menu.instant')})`,
129132
tooltip: t('menu.instantTooltip'),
130133
command: () => {
134+
useTelemetry()?.trackUiButtonClicked({
135+
button_id: 'queue_mode_option_run_instant_selected'
136+
})
131137
queueMode.value = 'instant'
132138
}
133139
}
@@ -160,6 +166,12 @@ const queuePrompt = async (e: Event) => {
160166
161167
useTelemetry()?.trackRunButton({ subscribe_to_run: false })
162168
169+
if (batchCount.value > 1) {
170+
useTelemetry()?.trackUiButtonClicked({
171+
button_id: 'queue_run_multiple_batches_submitted'
172+
})
173+
}
174+
163175
await commandStore.execute(commandId)
164176
}
165177
</script>

src/components/breadcrumb/SubgraphBreadcrumb.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { computed, onUpdated, ref, watch } from 'vue'
4040
4141
import SubgraphBreadcrumbItem from '@/components/breadcrumb/SubgraphBreadcrumbItem.vue'
4242
import { useOverflowObserver } from '@/composables/element/useOverflowObserver'
43+
import { useTelemetry } from '@/platform/telemetry'
4344
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
4445
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
4546
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
@@ -73,6 +74,9 @@ const items = computed(() => {
7374
const items = navigationStore.navigationStack.map<MenuItem>((subgraph) => ({
7475
label: subgraph.name,
7576
command: () => {
77+
useTelemetry()?.trackUiButtonClicked({
78+
button_id: 'breadcrumb_subgraph_item_selected'
79+
})
7680
const canvas = useCanvasStore().getCanvas()
7781
if (!canvas.graph) throw new TypeError('Canvas has no graph')
7882
@@ -97,6 +101,9 @@ const home = computed(() => ({
97101
key: 'root',
98102
isBlueprint: isBlueprint.value,
99103
command: () => {
104+
useTelemetry()?.trackUiButtonClicked({
105+
button_id: 'breadcrumb_subgraph_root_selected'
106+
})
100107
const canvas = useCanvasStore().getCanvas()
101108
if (!canvas.graph) throw new TypeError('Canvas has no graph')
102109

src/components/dialog/content/ErrorDialogContent.vue

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,13 @@ const repoOwner = 'comfyanonymous'
8787
const repoName = 'ComfyUI'
8888
const reportContent = ref('')
8989
const reportOpen = ref(false)
90+
/**
91+
* Open the error report content and track telemetry.
92+
*/
9093
const showReport = () => {
94+
useTelemetry()?.trackUiButtonClicked({
95+
button_id: 'error_dialog_show_report_clicked'
96+
})
9197
reportOpen.value = true
9298
}
9399
const toast = useToast()
@@ -99,6 +105,9 @@ const title = computed<string>(
99105
() => error.nodeType ?? error.exceptionType ?? t('errorDialog.defaultTitle')
100106
)
101107
108+
/**
109+
* Open contact support flow from error dialog and track telemetry.
110+
*/
102111
const showContactSupport = async () => {
103112
telemetry?.trackHelpResourceClicked({
104113
resource_type: 'help_feedback',

src/components/dialog/content/error/FindIssueButton.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import Button from 'primevue/button'
1212
import { computed } from 'vue'
1313
14+
import { useTelemetry } from '@/platform/telemetry'
15+
1416
const props = defineProps<{
1517
errorMessage: string
1618
repoOwner: string
@@ -19,7 +21,13 @@ const props = defineProps<{
1921
2022
const queryString = computed(() => props.errorMessage + ' is:issue')
2123
24+
/**
25+
* Open GitHub issues search and track telemetry.
26+
*/
2227
const openGitHubIssues = () => {
28+
useTelemetry()?.trackUiButtonClicked({
29+
button_id: 'error_dialog_find_existing_issues_clicked'
30+
})
2331
const query = encodeURIComponent(queryString.value)
2432
const url = `https://github.com/${props.repoOwner}/${props.repoName}/issues?q=${query}`
2533
window.open(url, '_blank')

src/components/dialog/content/setting/CreditsPanel.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ watch(
164164
)
165165
166166
const handlePurchaseCreditsClick = () => {
167+
// Track purchase credits entry from Settings > Credits panel
168+
useTelemetry()?.trackAddApiCreditButtonClicked()
167169
dialogService.showTopUpCreditsDialog()
168170
}
169171

src/components/graph/GraphCanvasMenu.vue

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
data-testid="toggle-minimap-button"
6262
:style="stringifiedMinimapStyles.buttonStyles"
6363
:class="minimapButtonClass"
64-
@click="() => commandStore.execute('Comfy.Canvas.ToggleMinimap')"
64+
@click="onMinimapToggleClick"
6565
>
6666
<template #icon>
6767
<i class="icon-[lucide--map] h-4 w-4" />
@@ -82,7 +82,7 @@
8282
:aria-label="linkVisibilityAriaLabel"
8383
data-testid="toggle-link-visibility-button"
8484
:style="stringifiedMinimapStyles.buttonStyles"
85-
@click="() => commandStore.execute('Comfy.Canvas.ToggleLinkVisibility')"
85+
@click="onLinkVisibilityToggleClick"
8686
>
8787
<template #icon>
8888
<i class="icon-[lucide--route-off] h-4 w-4" />
@@ -101,6 +101,7 @@ import { useI18n } from 'vue-i18n'
101101
import { useZoomControls } from '@/composables/useZoomControls'
102102
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
103103
import { useSettingStore } from '@/platform/settings/settingStore'
104+
import { useTelemetry } from '@/platform/telemetry'
104105
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
105106
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
106107
import { useMinimap } from '@/renderer/extensions/minimap/composables/useMinimap'
@@ -218,6 +219,26 @@ onMounted(() => {
218219
canvasStore.initScaleSync()
219220
})
220221
222+
/**
223+
* Track minimap toggle button click and execute the command.
224+
*/
225+
const onMinimapToggleClick = () => {
226+
useTelemetry()?.trackUiButtonClicked({
227+
button_id: 'graph_menu_minimap_toggle_clicked'
228+
})
229+
void commandStore.execute('Comfy.Canvas.ToggleMinimap')
230+
}
231+
232+
/**
233+
* Track hide/show links button click and execute the command.
234+
*/
235+
const onLinkVisibilityToggleClick = () => {
236+
useTelemetry()?.trackUiButtonClicked({
237+
button_id: 'graph_menu_hide_links_toggle_clicked'
238+
})
239+
void commandStore.execute('Comfy.Canvas.ToggleLinkVisibility')
240+
}
241+
221242
onBeforeUnmount(() => {
222243
canvasStore.cleanupScaleSync()
223244
})

src/components/graph/selectionToolbox/InfoButton.vue

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
data-testid="info-button"
88
text
99
severity="secondary"
10-
@click="toggleHelp"
10+
@click="onInfoClick"
1111
>
1212
<i class="icon-[lucide--info] h-4 w-4" />
1313
</Button>
@@ -17,6 +17,17 @@
1717
import Button from 'primevue/button'
1818
1919
import { useSelectionState } from '@/composables/graph/useSelectionState'
20+
import { useTelemetry } from '@/platform/telemetry'
2021
2122
const { showNodeHelp: toggleHelp } = useSelectionState()
23+
24+
/**
25+
* Track node info button click and toggle node help.
26+
*/
27+
const onInfoClick = () => {
28+
useTelemetry()?.trackUiButtonClicked({
29+
button_id: 'selection_toolbox_node_info_opened'
30+
})
31+
toggleHelp()
32+
}
2233
</script>

src/components/sidebar/ComfyMenuButton.vue

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
:class="{
55
'comfy-menu-button-active': menuRef?.visible
66
}"
7-
@click="menuRef?.toggle($event)"
7+
@click="onLogoMenuClick($event)"
88
>
99
<ComfyLogoTransparent
1010
alt="ComfyUI Logo"
@@ -78,6 +78,7 @@ import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.
7878
import ComfyLogoTransparent from '@/components/icons/ComfyLogoTransparent.vue'
7979
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
8080
import SettingDialogContent from '@/platform/settings/components/SettingDialogContent.vue'
81+
import { useTelemetry } from '@/platform/telemetry'
8182
import { useColorPaletteService } from '@/services/colorPaletteService'
8283
import { useCommandStore } from '@/stores/commandStore'
8384
import { useDialogStore } from '@/stores/dialogStore'
@@ -104,6 +105,15 @@ const menuRef = ref<
104105
({ dirty: boolean } & TieredMenuMethods & TieredMenuState) | null
105106
>(null)
106107
108+
const telemetry = useTelemetry()
109+
110+
function onLogoMenuClick(event: MouseEvent) {
111+
telemetry?.trackUiButtonClicked({
112+
button_id: 'sidebar_comfy_menu_opened'
113+
})
114+
menuRef.value?.toggle(event)
115+
}
116+
107117
const translateMenuItem = (item: MenuItem): MenuItem => {
108118
const label = typeof item.label === 'function' ? item.label() : item.label
109119
const translatedLabel = label
@@ -167,7 +177,12 @@ const extraMenuItems = computed(() => [
167177
key: 'settings',
168178
label: t('g.settings'),
169179
icon: 'mdi mdi-cog-outline',
170-
command: () => showSettings()
180+
command: () => {
181+
telemetry?.trackUiButtonClicked({
182+
button_id: 'sidebar_settings_menu_opened'
183+
})
184+
showSettings()
185+
}
171186
},
172187
{
173188
key: 'manage-extensions',

src/components/sidebar/SideToolbar.vue

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import ComfyMenuButton from '@/components/sidebar/ComfyMenuButton.vue'
5757
import SidebarBottomPanelToggleButton from '@/components/sidebar/SidebarBottomPanelToggleButton.vue'
5858
import SidebarShortcutsToggleButton from '@/components/sidebar/SidebarShortcutsToggleButton.vue'
5959
import { useSettingStore } from '@/platform/settings/settingStore'
60+
import { useTelemetry } from '@/platform/telemetry'
6061
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
6162
import { useCommandStore } from '@/stores/commandStore'
6263
import { useKeybindingStore } from '@/stores/keybindingStore'
@@ -97,10 +98,40 @@ const isConnected = computed(
9798
const tabs = computed(() => workspaceStore.getSidebarTabs())
9899
const selectedTab = computed(() => workspaceStore.sidebarTab.activeSidebarTab)
99100
100-
const onTabClick = async (item: SidebarTabExtension) =>
101+
/**
102+
* Handle sidebar tab icon click.
103+
* - Emits UI button telemetry for known tabs
104+
* - Delegates to the corresponding toggle command
105+
*/
106+
const onTabClick = async (item: SidebarTabExtension) => {
107+
const telemetry = useTelemetry()
108+
109+
const isNodeLibraryTab = item.id === 'node-library'
110+
const isModelLibraryTab = item.id === 'model-library'
111+
const isWorkflowsTab = item.id === 'workflows'
112+
const isAssetsTab = item.id === 'assets'
113+
114+
if (isNodeLibraryTab)
115+
telemetry?.trackUiButtonClicked({
116+
button_id: 'sidebar_tab_node_library_selected'
117+
})
118+
else if (isModelLibraryTab)
119+
telemetry?.trackUiButtonClicked({
120+
button_id: 'sidebar_tab_model_library_selected'
121+
})
122+
else if (isWorkflowsTab)
123+
telemetry?.trackUiButtonClicked({
124+
button_id: 'sidebar_tab_workflows_selected'
125+
})
126+
else if (isAssetsTab)
127+
telemetry?.trackUiButtonClicked({
128+
button_id: 'sidebar_tab_assets_media_selected'
129+
})
130+
101131
await commandStore.commands
102132
.find((cmd) => cmd.id === `Workspace.ToggleSidebarTab.${item.id}`)
103133
?.function?.()
134+
}
104135
105136
const keybindingStore = useKeybindingStore()
106137
const getTabTooltipSuffix = (tab: SidebarTabExtension) => {

0 commit comments

Comments
 (0)