Skip to content
8 changes: 8 additions & 0 deletions src/components/actionbar/ComfyActionbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { computed, nextTick, onMounted, ref, watch } from 'vue'

import { t } from '@/i18n'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useTelemetry } from '@/platform/telemetry'
import { cn } from '@/utils/tailwindUtil'

import ComfyRunButton from './ComfyRunButton'
Expand Down Expand Up @@ -132,6 +133,13 @@ watch(visible, async (newVisible) => {
}
})

/**
* Track run button handle drag start using mousedown on the drag handle.
*/
useEventListener(dragHandleRef, 'mousedown', () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'run_button_handle' })
})

const lastDragState = ref({
x: x.value,
y: y.value,
Expand Down
8 changes: 7 additions & 1 deletion src/components/actionbar/ComfyRunButton/ComfyQueueButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ import BatchCountEdit from '../BatchCountEdit.vue'

const workspaceStore = useWorkspaceStore()
const queueCountStore = storeToRefs(useQueuePendingTaskCountStore())
const { mode: queueMode } = storeToRefs(useQueueSettingsStore())
const { mode: queueMode, batchCount } = storeToRefs(useQueueSettingsStore())

const { t } = useI18n()
const queueModeMenuItemLookup = computed(() => {
Expand All @@ -118,6 +118,7 @@ const queueModeMenuItemLookup = computed(() => {
label: `${t('menu.run')} (${t('menu.onChange')})`,
tooltip: t('menu.onChangeTooltip'),
command: () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'run_on_change' })
queueMode.value = 'change'
}
}
Expand All @@ -128,6 +129,7 @@ const queueModeMenuItemLookup = computed(() => {
label: `${t('menu.run')} (${t('menu.instant')})`,
tooltip: t('menu.instantTooltip'),
command: () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'run_instant' })
queueMode.value = 'instant'
}
}
Expand Down Expand Up @@ -160,6 +162,10 @@ const queuePrompt = async (e: Event) => {

useTelemetry()?.trackRunButton({ subscribe_to_run: false })

if (batchCount.value > 1) {
useTelemetry()?.trackUiButtonClicked({ button_id: 'queue_multiple' })
}

await commandStore.execute(commandId)
}
</script>
Expand Down
7 changes: 7 additions & 0 deletions src/components/breadcrumb/SubgraphBreadcrumb.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { computed, onUpdated, ref, watch } from 'vue'

import SubgraphBreadcrumbItem from '@/components/breadcrumb/SubgraphBreadcrumbItem.vue'
import { useOverflowObserver } from '@/composables/element/useOverflowObserver'
import { useTelemetry } from '@/platform/telemetry'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
Expand Down Expand Up @@ -73,6 +74,9 @@ const items = computed(() => {
const items = navigationStore.navigationStack.map<MenuItem>((subgraph) => ({
label: subgraph.name,
command: () => {
useTelemetry()?.trackUiButtonClicked({
button_id: 'subgraph_breadcrumb_item'
})
const canvas = useCanvasStore().getCanvas()
if (!canvas.graph) throw new TypeError('Canvas has no graph')

Expand All @@ -97,6 +101,9 @@ const home = computed(() => ({
key: 'root',
isBlueprint: isBlueprint.value,
command: () => {
useTelemetry()?.trackUiButtonClicked({
button_id: 'subgraph_breadcrumb_root'
})
const canvas = useCanvasStore().getCanvas()
if (!canvas.graph) throw new TypeError('Canvas has no graph')

Expand Down
7 changes: 7 additions & 0 deletions src/components/dialog/content/ErrorDialogContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,11 @@ const repoOwner = 'comfyanonymous'
const repoName = 'ComfyUI'
const reportContent = ref('')
const reportOpen = ref(false)
/**
* Open the error report content and track telemetry.
*/
const showReport = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'error_show_report' })
reportOpen.value = true
}
const toast = useToast()
Expand All @@ -99,6 +103,9 @@ const title = computed<string>(
() => error.nodeType ?? error.exceptionType ?? t('errorDialog.defaultTitle')
)

/**
* Open contact support flow from error dialog and track telemetry.
*/
const showContactSupport = async () => {
telemetry?.trackHelpResourceClicked({
resource_type: 'help_feedback',
Expand Down
6 changes: 6 additions & 0 deletions src/components/dialog/content/error/FindIssueButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import Button from 'primevue/button'
import { computed } from 'vue'

import { useTelemetry } from '@/platform/telemetry'

const props = defineProps<{
errorMessage: string
repoOwner: string
Expand All @@ -19,7 +21,11 @@ const props = defineProps<{

const queryString = computed(() => props.errorMessage + ' is:issue')

/**
* Open GitHub issues search and track telemetry.
*/
const openGitHubIssues = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'error_find_issues' })
const query = encodeURIComponent(queryString.value)
const url = `https://github.com/${props.repoOwner}/${props.repoName}/issues?q=${query}`
window.open(url, '_blank')
Expand Down
2 changes: 2 additions & 0 deletions src/components/dialog/content/setting/CreditsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ watch(
)

const handlePurchaseCreditsClick = () => {
// Track purchase credits entry from Settings > Credits panel
useTelemetry()?.trackAddApiCreditButtonClicked()
dialogService.showTopUpCreditsDialog()
}

Expand Down
21 changes: 19 additions & 2 deletions src/components/graph/GraphCanvasMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
data-testid="toggle-minimap-button"
:style="stringifiedMinimapStyles.buttonStyles"
:class="minimapButtonClass"
@click="() => commandStore.execute('Comfy.Canvas.ToggleMinimap')"
@click="onMinimapToggleClick"
>
<template #icon>
<i class="icon-[lucide--map] h-4 w-4" />
Expand All @@ -82,7 +82,7 @@
:aria-label="linkVisibilityAriaLabel"
data-testid="toggle-link-visibility-button"
:style="stringifiedMinimapStyles.buttonStyles"
@click="() => commandStore.execute('Comfy.Canvas.ToggleLinkVisibility')"
@click="onLinkVisibilityToggleClick"
>
<template #icon>
<i class="icon-[lucide--route-off] h-4 w-4" />
Expand All @@ -101,6 +101,7 @@ import { useI18n } from 'vue-i18n'
import { useZoomControls } from '@/composables/useZoomControls'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useTelemetry } from '@/platform/telemetry'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCanvasInteractions } from '@/renderer/core/canvas/useCanvasInteractions'
import { useMinimap } from '@/renderer/extensions/minimap/composables/useMinimap'
Expand Down Expand Up @@ -218,6 +219,22 @@ onMounted(() => {
canvasStore.initScaleSync()
})

/**
* Track minimap toggle button click and execute the command.
*/
const onMinimapToggleClick = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'minimap_toggle' })
void commandStore.execute('Comfy.Canvas.ToggleMinimap')
}

/**
* Track hide/show links button click and execute the command.
*/
const onLinkVisibilityToggleClick = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'hide_links' })
void commandStore.execute('Comfy.Canvas.ToggleLinkVisibility')
}

onBeforeUnmount(() => {
canvasStore.cleanupScaleSync()
})
Expand Down
11 changes: 10 additions & 1 deletion src/components/graph/selectionToolbox/InfoButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
data-testid="info-button"
text
severity="secondary"
@click="toggleHelp"
@click="onInfoClick"
>
<i class="icon-[lucide--info] h-4 w-4" />
</Button>
Expand All @@ -17,6 +17,15 @@
import Button from 'primevue/button'

import { useSelectionState } from '@/composables/graph/useSelectionState'
import { useTelemetry } from '@/platform/telemetry'

const { showNodeHelp: toggleHelp } = useSelectionState()

/**
* Track node info button click and toggle node help.
*/
const onInfoClick = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'node_info' })
toggleHelp()
}
</script>
15 changes: 13 additions & 2 deletions src/components/sidebar/ComfyMenuButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
:class="{
'comfy-menu-button-active': menuRef?.visible
}"
@click="menuRef?.toggle($event)"
@click="onLogoMenuClick($event)"
>
<ComfyLogoTransparent
alt="ComfyUI Logo"
Expand Down Expand Up @@ -78,6 +78,7 @@ import SettingDialogHeader from '@/components/dialog/header/SettingDialogHeader.
import ComfyLogoTransparent from '@/components/icons/ComfyLogoTransparent.vue'
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
import SettingDialogContent from '@/platform/settings/components/SettingDialogContent.vue'
import { useTelemetry } from '@/platform/telemetry'
import { useColorPaletteService } from '@/services/colorPaletteService'
import { useCommandStore } from '@/stores/commandStore'
import { useDialogStore } from '@/stores/dialogStore'
Expand All @@ -104,6 +105,13 @@ const menuRef = ref<
({ dirty: boolean } & TieredMenuMethods & TieredMenuState) | null
>(null)

const telemetry = useTelemetry()

function onLogoMenuClick(event: MouseEvent) {
telemetry?.trackUiButtonClicked({ button_id: 'comfy_logo' })
menuRef.value?.toggle(event)
}

const translateMenuItem = (item: MenuItem): MenuItem => {
const label = typeof item.label === 'function' ? item.label() : item.label
const translatedLabel = label
Expand Down Expand Up @@ -167,7 +175,10 @@ const extraMenuItems = computed(() => [
key: 'settings',
label: t('g.settings'),
icon: 'mdi mdi-cog-outline',
command: () => showSettings()
command: () => {
telemetry?.trackUiButtonClicked({ button_id: 'settings_menu' })
showSettings()
}
},
{
key: 'manage-extensions',
Expand Down
24 changes: 23 additions & 1 deletion src/components/sidebar/SideToolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import ComfyMenuButton from '@/components/sidebar/ComfyMenuButton.vue'
import SidebarBottomPanelToggleButton from '@/components/sidebar/SidebarBottomPanelToggleButton.vue'
import SidebarShortcutsToggleButton from '@/components/sidebar/SidebarShortcutsToggleButton.vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useTelemetry } from '@/platform/telemetry'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import { useCommandStore } from '@/stores/commandStore'
import { useKeybindingStore } from '@/stores/keybindingStore'
Expand Down Expand Up @@ -97,10 +98,31 @@ const isConnected = computed(
const tabs = computed(() => workspaceStore.getSidebarTabs())
const selectedTab = computed(() => workspaceStore.sidebarTab.activeSidebarTab)

const onTabClick = async (item: SidebarTabExtension) =>
/**
* Handle sidebar tab icon click.
* - Emits UI button telemetry for known tabs
* - Delegates to the corresponding toggle command
*/
const onTabClick = async (item: SidebarTabExtension) => {
const telemetry = useTelemetry()

const isNodeLibraryTab = item.id === 'node-library'
const isModelLibraryTab = item.id === 'model-library'
const isWorkflowsTab = item.id === 'workflows'
const isAssetsTab = item.id === 'assets'

if (isNodeLibraryTab)
telemetry?.trackUiButtonClicked({ button_id: 'node_library' })
else if (isModelLibraryTab)
telemetry?.trackUiButtonClicked({ button_id: 'model_library' })
else if (isWorkflowsTab)
telemetry?.trackUiButtonClicked({ button_id: 'workflows' })
else if (isAssetsTab) telemetry?.trackUiButtonClicked({ button_id: 'assets' })

await commandStore.commands
.find((cmd) => cmd.id === `Workspace.ToggleSidebarTab.${item.id}`)
?.function?.()
}

const keybindingStore = useKeybindingStore()
const getTabTooltipSuffix = (tab: SidebarTabExtension) => {
Expand Down
11 changes: 10 additions & 1 deletion src/components/sidebar/SidebarBottomPanelToggleButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
:label="$t('sideToolbar.labels.console')"
:tooltip="$t('menu.toggleBottomPanel')"
:selected="bottomPanelStore.activePanel == 'terminal'"
@click="bottomPanelStore.toggleBottomPanel"
@click="toggleConsole"
>
<template #icon>
<i-ph:terminal-bold />
Expand All @@ -12,9 +12,18 @@
</template>

<script setup lang="ts">
import { useTelemetry } from '@/platform/telemetry'
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'

import SidebarIcon from './SidebarIcon.vue'

const bottomPanelStore = useBottomPanelStore()

/**
* Toggle console bottom panel and track UI button click.
*/
const toggleConsole = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'console' })
bottomPanelStore.toggleBottomPanel()
}
</script>
5 changes: 5 additions & 0 deletions src/components/sidebar/SidebarHelpCenterIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import { computed, onMounted, toRefs } from 'vue'

import HelpCenterMenuContent from '@/components/helpcenter/HelpCenterMenuContent.vue'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useTelemetry } from '@/platform/telemetry'
import { useReleaseStore } from '@/platform/updates/common/releaseStore'
import ReleaseNotificationToast from '@/platform/updates/components/ReleaseNotificationToast.vue'
import WhatsNewPopup from '@/platform/updates/components/WhatsNewPopup.vue'
Expand Down Expand Up @@ -104,7 +105,11 @@ const sidebarLocation = computed(() =>
settingStore.get('Comfy.Sidebar.Location')
)

/**
* Toggle Help Center and track UI button click.
*/
const toggleHelpCenter = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'help_center' })
helpCenterStore.toggle()
}

Expand Down
5 changes: 5 additions & 0 deletions src/components/sidebar/SidebarShortcutsToggleButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'

import { useTelemetry } from '@/platform/telemetry'
import { useCommandStore } from '@/stores/commandStore'
import { useBottomPanelStore } from '@/stores/workspace/bottomPanelStore'

Expand All @@ -34,7 +35,11 @@ const tooltipText = computed(
() => `${t('shortcuts.keyboardShortcuts')} (${formatKeySequence(command)})`
)

/**
* Toggle keyboard shortcuts panel and track UI button click.
*/
const toggleShortcutsPanel = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'keyboard_shortcuts' })
bottomPanelStore.togglePanel('shortcuts')
}
</script>
5 changes: 5 additions & 0 deletions src/components/sidebar/SidebarTemplatesButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { computed } from 'vue'

import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
import { useSettingStore } from '@/platform/settings/settingStore'
import { useTelemetry } from '@/platform/telemetry'

import SidebarIcon from './SidebarIcon.vue'

Expand All @@ -23,7 +24,11 @@ const isSmall = computed(
() => settingStore.get('Comfy.Sidebar.Size') === 'small'
)

/**
* Open templates dialog from sidebar and track UI button click.
*/
const openTemplates = () => {
useTelemetry()?.trackUiButtonClicked({ button_id: 'templates' })
useWorkflowTemplateSelectorDialog().show('sidebar')
}
</script>
Loading