mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-08 00:50:05 +00:00
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 <cbyrne@comfy.org> Co-authored-by: Claude <noreply@anthropic.com>
154 lines
4.3 KiB
Vue
154 lines
4.3 KiB
Vue
<template>
|
|
<div class="comfy-error-report flex flex-col gap-4">
|
|
<NoResultsPlaceholder
|
|
class="pb-0"
|
|
icon="pi pi-exclamation-circle"
|
|
:title="title"
|
|
:message="error.exceptionMessage"
|
|
:text-class="'break-words max-w-[60vw]'"
|
|
/>
|
|
<template v-if="error.extensionFile">
|
|
<span>{{ t('errorDialog.extensionFileHint') }}:</span>
|
|
<br />
|
|
<span class="font-bold">{{ error.extensionFile }}</span>
|
|
</template>
|
|
|
|
<div class="flex justify-center gap-2">
|
|
<Button
|
|
v-show="!reportOpen"
|
|
text
|
|
:label="$t('g.showReport')"
|
|
@click="showReport"
|
|
/>
|
|
<Button
|
|
v-show="!reportOpen"
|
|
text
|
|
:label="$t('issueReport.helpFix')"
|
|
@click="showContactSupport"
|
|
/>
|
|
</div>
|
|
<template v-if="reportOpen">
|
|
<Divider />
|
|
<ScrollPanel class="h-[400px] w-full max-w-[80vw]">
|
|
<pre class="break-words whitespace-pre-wrap">{{ reportContent }}</pre>
|
|
</ScrollPanel>
|
|
<Divider />
|
|
</template>
|
|
<div class="flex justify-end gap-4">
|
|
<FindIssueButton
|
|
:error-message="error.exceptionMessage"
|
|
:repo-owner="repoOwner"
|
|
:repo-name="repoName"
|
|
/>
|
|
<Button
|
|
v-if="reportOpen"
|
|
:label="$t('g.copyToClipboard')"
|
|
icon="pi pi-copy"
|
|
@click="copyReportToClipboard"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import Button from 'primevue/button'
|
|
import Divider from 'primevue/divider'
|
|
import ScrollPanel from 'primevue/scrollpanel'
|
|
import { useToast } from 'primevue/usetoast'
|
|
import { computed, onMounted, ref } from 'vue'
|
|
import { useI18n } from 'vue-i18n'
|
|
|
|
import NoResultsPlaceholder from '@/components/common/NoResultsPlaceholder.vue'
|
|
import FindIssueButton from '@/components/dialog/content/error/FindIssueButton.vue'
|
|
import { useCopyToClipboard } from '@/composables/useCopyToClipboard'
|
|
import { useTelemetry } from '@/platform/telemetry'
|
|
import { api } from '@/scripts/api'
|
|
import { app } from '@/scripts/app'
|
|
import { useCommandStore } from '@/stores/commandStore'
|
|
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
|
import { generateErrorReport } from '@/utils/errorReportUtil'
|
|
import type { ErrorReportData } from '@/utils/errorReportUtil'
|
|
|
|
const { error } = defineProps<{
|
|
error: Omit<ErrorReportData, 'workflow' | 'systemStats' | 'serverLogs'> & {
|
|
/**
|
|
* The type of error report to submit.
|
|
* @default 'unknownError'
|
|
*/
|
|
reportType?: string
|
|
/**
|
|
* The file name of the extension that caused the error.
|
|
*/
|
|
extensionFile?: string
|
|
}
|
|
}>()
|
|
|
|
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_dialog_show_report_clicked'
|
|
})
|
|
reportOpen.value = true
|
|
}
|
|
const toast = useToast()
|
|
const { t } = useI18n()
|
|
const systemStatsStore = useSystemStatsStore()
|
|
const telemetry = useTelemetry()
|
|
|
|
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',
|
|
is_external: true,
|
|
source: 'error_dialog'
|
|
})
|
|
await useCommandStore().execute('Comfy.ContactSupport')
|
|
}
|
|
|
|
onMounted(async () => {
|
|
if (!systemStatsStore.systemStats) {
|
|
await systemStatsStore.refetchSystemStats()
|
|
}
|
|
|
|
try {
|
|
const [logs] = await Promise.all([api.getLogs()])
|
|
|
|
reportContent.value = generateErrorReport({
|
|
systemStats: systemStatsStore.systemStats!,
|
|
serverLogs: logs,
|
|
workflow: app.graph.serialize(),
|
|
exceptionType: error.exceptionType,
|
|
exceptionMessage: error.exceptionMessage,
|
|
traceback: error.traceback,
|
|
nodeId: error.nodeId,
|
|
nodeType: error.nodeType
|
|
})
|
|
} catch (error) {
|
|
console.error('Error fetching logs:', error)
|
|
toast.add({
|
|
severity: 'error',
|
|
summary: t('g.error'),
|
|
detail: t('toastMessages.failedToFetchLogs'),
|
|
life: 5000
|
|
})
|
|
}
|
|
})
|
|
|
|
const { copyToClipboard } = useCopyToClipboard()
|
|
const copyReportToClipboard = async () => {
|
|
await copyToClipboard(reportContent.value)
|
|
}
|
|
</script>
|