mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-23 08:14:06 +00:00
[Refactor] Unify error dialog component (#3265)
Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
@@ -1,80 +1,159 @@
|
||||
<template>
|
||||
<div class="error-dialog-content flex flex-col gap-4">
|
||||
<div class="comfy-error-report flex flex-col gap-4">
|
||||
<NoResultsPlaceholder
|
||||
class="pb-0"
|
||||
icon="pi pi-exclamation-circle"
|
||||
:title="title"
|
||||
:message="errorMessage"
|
||||
:message="error.exceptionMessage"
|
||||
/>
|
||||
<pre
|
||||
class="stack-trace p-5 text-neutral-400 text-xs max-h-[50vh] overflow-auto bg-black/20"
|
||||
>
|
||||
{{ stackTrace }}
|
||||
</pre>
|
||||
|
||||
<template v-if="extensionFile">
|
||||
<template v-if="error.extensionFile">
|
||||
<span>{{ t('errorDialog.extensionFileHint') }}:</span>
|
||||
<br />
|
||||
<span class="font-bold">{{ extensionFile }}</span>
|
||||
<span class="font-bold">{{ error.extensionFile }}</span>
|
||||
</template>
|
||||
|
||||
<Button
|
||||
v-show="!sendReportOpen"
|
||||
text
|
||||
fluid
|
||||
:label="$t('issueReport.helpFix')"
|
||||
@click="showSendReport"
|
||||
/>
|
||||
|
||||
<div class="flex gap-2 justify-center">
|
||||
<Button
|
||||
v-show="!reportOpen"
|
||||
text
|
||||
:label="$t('g.showReport')"
|
||||
@click="showReport"
|
||||
/>
|
||||
<Button
|
||||
v-show="!sendReportOpen"
|
||||
text
|
||||
:label="$t('issueReport.helpFix')"
|
||||
@click="showSendReport"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="reportOpen">
|
||||
<Divider />
|
||||
<ScrollPanel class="w-full h-[400px] max-w-[80vw]">
|
||||
<pre class="whitespace-pre-wrap break-words">{{ reportContent }}</pre>
|
||||
</ScrollPanel>
|
||||
<Divider />
|
||||
</template>
|
||||
<ReportIssuePanel
|
||||
v-if="sendReportOpen"
|
||||
:error-type="errorType"
|
||||
:extra-fields="[
|
||||
{
|
||||
label: t('issueReport.stackTrace'),
|
||||
value: 'StackTrace',
|
||||
optIn: true,
|
||||
getData: () => stackTrace
|
||||
}
|
||||
]"
|
||||
:title="$t('issueReport.submitErrorReport')"
|
||||
:error-type="error.reportType ?? 'unknownError'"
|
||||
:extra-fields="[stackTraceField]"
|
||||
:tags="{
|
||||
exceptionMessage: errorMessage,
|
||||
extensionFile: extensionFile ?? 'UNKNOWN'
|
||||
exceptionMessage: error.exceptionMessage,
|
||||
nodeType: error.nodeType ?? 'UNKNOWN'
|
||||
}"
|
||||
:title="t('issueReport.submitErrorReport')"
|
||||
/>
|
||||
<div class="flex gap-4 justify-end">
|
||||
<FindIssueButton
|
||||
:errorMessage="error.exceptionMessage"
|
||||
:repoOwner="repoOwner"
|
||||
:repoName="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 { computed, ref } from 'vue'
|
||||
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 { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import type { ReportField } from '@/types/issueReportTypes'
|
||||
import {
|
||||
type ErrorReportData,
|
||||
generateErrorReport
|
||||
} from '@/utils/errorReportUtil'
|
||||
|
||||
import ReportIssuePanel from './error/ReportIssuePanel.vue'
|
||||
|
||||
const { t } = useI18n()
|
||||
const {
|
||||
title: _title,
|
||||
errorMessage,
|
||||
stackTrace: _stackTrace,
|
||||
extensionFile,
|
||||
errorType = 'frontendError'
|
||||
} = defineProps<{
|
||||
title?: string
|
||||
errorMessage: string
|
||||
stackTrace?: string
|
||||
extensionFile?: string
|
||||
errorType?: string
|
||||
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 title = computed(() => _title ?? t('errorDialog.defaultTitle'))
|
||||
const stackTrace = computed(() => _stackTrace ?? t('errorDialog.noStackTrace'))
|
||||
|
||||
const repoOwner = 'comfyanonymous'
|
||||
const repoName = 'ComfyUI'
|
||||
const reportContent = ref('')
|
||||
const reportOpen = ref(false)
|
||||
const showReport = () => {
|
||||
reportOpen.value = true
|
||||
}
|
||||
const sendReportOpen = ref(false)
|
||||
function showSendReport() {
|
||||
const showSendReport = () => {
|
||||
sendReportOpen.value = true
|
||||
}
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
const systemStatsStore = useSystemStatsStore()
|
||||
|
||||
const title = computed<string>(
|
||||
() => error.nodeType ?? error.exceptionType ?? t('errorDialog.defaultTitle')
|
||||
)
|
||||
|
||||
const stackTraceField = computed<ReportField>(() => {
|
||||
return {
|
||||
label: t('issueReport.stackTrace'),
|
||||
value: 'StackTrace',
|
||||
optIn: true,
|
||||
getData: () => error.traceback
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
if (!systemStatsStore.systemStats) {
|
||||
await systemStatsStore.fetchSystemStats()
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
<template>
|
||||
<NoResultsPlaceholder
|
||||
icon="pi pi-exclamation-circle"
|
||||
:title="error.node_type"
|
||||
:message="error.exception_message"
|
||||
/>
|
||||
<div class="comfy-error-report">
|
||||
<div class="flex gap-2 justify-center">
|
||||
<Button
|
||||
v-show="!reportOpen"
|
||||
text
|
||||
:label="$t('g.showReport')"
|
||||
@click="showReport"
|
||||
/>
|
||||
<Button
|
||||
v-show="!sendReportOpen"
|
||||
text
|
||||
:label="$t('issueReport.helpFix')"
|
||||
@click="showSendReport"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="reportOpen">
|
||||
<Divider />
|
||||
<ScrollPanel style="width: 100%; height: 400px; max-width: 80vw">
|
||||
<pre class="wrapper-pre">{{ reportContent }}</pre>
|
||||
</ScrollPanel>
|
||||
<Divider />
|
||||
</template>
|
||||
<ReportIssuePanel
|
||||
v-if="sendReportOpen"
|
||||
:title="$t('issueReport.submitErrorReport')"
|
||||
error-type="graphExecutionError"
|
||||
:extra-fields="[stackTraceField]"
|
||||
:tags="{
|
||||
exceptionMessage: error.exception_message,
|
||||
nodeType: error.node_type
|
||||
}"
|
||||
/>
|
||||
<div class="action-container">
|
||||
<FindIssueButton
|
||||
:errorMessage="error.exception_message"
|
||||
:repoOwner="repoOwner"
|
||||
:repoName="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 type { ExecutionErrorWsMessage, SystemStats } from '@/schemas/apiSchema'
|
||||
import { api } from '@/scripts/api'
|
||||
import { app } from '@/scripts/app'
|
||||
import type { ReportField } from '@/types/issueReportTypes'
|
||||
import { generateErrorReport } from '@/utils/errorReportUtil'
|
||||
|
||||
import ReportIssuePanel from './error/ReportIssuePanel.vue'
|
||||
|
||||
const { error } = defineProps<{
|
||||
error: ExecutionErrorWsMessage
|
||||
}>()
|
||||
|
||||
const repoOwner = 'comfyanonymous'
|
||||
const repoName = 'ComfyUI'
|
||||
const reportContent = ref('')
|
||||
const reportOpen = ref(false)
|
||||
const showReport = () => {
|
||||
reportOpen.value = true
|
||||
}
|
||||
const sendReportOpen = ref(false)
|
||||
const showSendReport = () => {
|
||||
sendReportOpen.value = true
|
||||
}
|
||||
const toast = useToast()
|
||||
const { t } = useI18n()
|
||||
|
||||
const stackTraceField = computed<ReportField>(() => {
|
||||
return {
|
||||
label: t('issueReport.stackTrace'),
|
||||
value: 'StackTrace',
|
||||
optIn: true,
|
||||
getData: () => error.traceback?.join('\n')
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const [systemStats, logs] = await Promise.all([
|
||||
api.getSystemStats(),
|
||||
api.getLogs()
|
||||
])
|
||||
generateReport(systemStats, logs)
|
||||
} catch (error) {
|
||||
console.error('Error fetching system stats or logs:', error)
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'Failed to fetch system information',
|
||||
life: 5000
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const generateReport = (systemStats: SystemStats, logs: string) => {
|
||||
reportContent.value = generateErrorReport({
|
||||
systemStats,
|
||||
serverLogs: logs,
|
||||
workflow: app.graph.serialize(),
|
||||
exception_type: error.exception_type,
|
||||
exception_message: error.exception_message,
|
||||
traceback: error.traceback,
|
||||
node_id: error.node_id,
|
||||
node_type: error.node_type
|
||||
})
|
||||
}
|
||||
|
||||
const { copyToClipboard } = useCopyToClipboard()
|
||||
const copyReportToClipboard = async () => {
|
||||
await copyToClipboard(reportContent.value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.comfy-error-report {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.action-container {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.wrapper-pre {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user