mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-19 13:59:28 +00:00
## Summary Refactors the error system to improve separation of concerns, fix DDD layer violations, and address code quality issues. - Extract `missingNodesErrorStore` from `executionErrorStore`, removing the delegation pattern that coupled missing-node logic into the execution error store - Extract `useNodeErrorFlagSync` composable for node error flag reconciliation (previously inlined) - Extract `useErrorClearingHooks` composable with explicit callback cleanup on node removal - Extract `useErrorActions` composable to deduplicate telemetry+command patterns across error card components - Move `getCnrIdFromNode`/`getCnrIdFromProperties` to `platform/nodeReplacement` layer (DDD fix) - Move `missingNodesErrorStore` to `platform/nodeReplacement` (DDD alignment) - Add unmount cancellation guard to `useErrorReport` async `onMounted` - Return watch stop handle from `useNodeErrorFlagSync` - Add `asyncResolvedIds` eviction on `missingNodesError` reset - Add `console.warn` to silent catch blocks and empty array guard - Hoist `useCommandStore` to setup scope, fix floating promises - Add `data-testid` to error groups, image/video error spans, copy button - Update E2E tests to use scoped locators and testids - Add unit tests for `onNodeRemoved` restoration and double-install guard Fixes #9875, Fixes #10027, Fixes #10033, Fixes #10085 ## Test plan - [x] Existing unit tests pass with updated imports and mocks - [x] New unit tests for `useErrorClearingHooks` (callback restoration, double-install guard) - [x] E2E tests updated to use scoped locators and `data-testid` - [ ] Manual: verify error tab shows runtime errors and missing nodes correctly - [ ] Manual: verify "Find on GitHub", "Copy", and "Get Help" buttons work in error cards ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10302-refactor-error-system-cleanup-store-separation-DDD-fix-test-improvements-3286d73d365081838279d045b8dd957a) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com>
94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
import { computed, onMounted, onUnmounted, reactive, toValue } from 'vue'
|
|
|
|
import type { MaybeRefOrGetter } from 'vue'
|
|
|
|
import { until } from '@vueuse/core'
|
|
|
|
import { api } from '@/scripts/api'
|
|
import { app } from '@/scripts/app'
|
|
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
|
import { generateErrorReport } from '@/utils/errorReportUtil'
|
|
|
|
import type { ErrorCardData } from './types'
|
|
|
|
/** Fallback exception type for error reports when the backend does not provide one. Not i18n'd: used in diagnostic reports only. */
|
|
const FALLBACK_EXCEPTION_TYPE = 'Runtime Error'
|
|
|
|
export function useErrorReport(cardSource: MaybeRefOrGetter<ErrorCardData>) {
|
|
const systemStatsStore = useSystemStatsStore()
|
|
const enrichedDetails = reactive<Record<number, string>>({})
|
|
|
|
const displayedDetailsMap = computed(() => {
|
|
const card = toValue(cardSource)
|
|
return Object.fromEntries(
|
|
card.errors.map((error, idx) => [
|
|
idx,
|
|
enrichedDetails[idx] ?? error.details
|
|
])
|
|
)
|
|
})
|
|
|
|
let cancelled = false
|
|
onUnmounted(() => {
|
|
cancelled = true
|
|
})
|
|
|
|
onMounted(async () => {
|
|
const card = toValue(cardSource)
|
|
const runtimeErrors = card.errors
|
|
.map((error, idx) => ({ error, idx }))
|
|
.filter(({ error }) => error.isRuntimeError)
|
|
|
|
if (runtimeErrors.length === 0) return
|
|
|
|
if (!systemStatsStore.systemStats) {
|
|
if (systemStatsStore.isLoading) {
|
|
await until(systemStatsStore.isLoading).toBe(false)
|
|
} else {
|
|
try {
|
|
await systemStatsStore.refetchSystemStats()
|
|
} catch (e) {
|
|
console.warn('Failed to fetch system stats for error report:', e)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
if (!systemStatsStore.systemStats || cancelled) return
|
|
|
|
const logs = await api
|
|
.getLogs()
|
|
.catch(() => 'Failed to retrieve server logs')
|
|
if (cancelled) return
|
|
|
|
const workflow = (() => {
|
|
try {
|
|
return app.rootGraph.serialize()
|
|
} catch (e) {
|
|
console.warn('Failed to serialize workflow for error report:', e)
|
|
return null
|
|
}
|
|
})()
|
|
if (!workflow) return
|
|
|
|
for (const { error, idx } of runtimeErrors) {
|
|
try {
|
|
const report = generateErrorReport({
|
|
exceptionType: error.exceptionType ?? FALLBACK_EXCEPTION_TYPE,
|
|
exceptionMessage: error.message,
|
|
traceback: error.details,
|
|
nodeId: card.nodeId,
|
|
nodeType: card.title,
|
|
systemStats: systemStatsStore.systemStats,
|
|
serverLogs: logs,
|
|
workflow
|
|
})
|
|
enrichedDetails[idx] = report
|
|
} catch (e) {
|
|
console.warn('Failed to generate error report:', e)
|
|
}
|
|
}
|
|
})
|
|
|
|
return { displayedDetailsMap }
|
|
}
|