[API Node] Contact support button (#3571)

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Christian Byrne
2025-04-23 07:47:23 +08:00
committed by GitHub
parent 9e247063aa
commit 1bcf5e28d4
22 changed files with 360 additions and 88 deletions

View File

@@ -25,6 +25,13 @@
:label="$t('issueReport.helpFix')"
@click="showSendReport"
/>
<Button
v-if="authStore.currentUser"
v-show="!reportOpen"
text
:label="$t('issueReport.contactSupportTitle')"
@click="showContactSupport"
/>
</div>
<template v-if="reportOpen">
<Divider />
@@ -72,6 +79,8 @@ import FindIssueButton from '@/components/dialog/content/error/FindIssueButton.v
import { useCopyToClipboard } from '@/composables/useCopyToClipboard'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useCommandStore } from '@/stores/commandStore'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useSystemStatsStore } from '@/stores/systemStatsStore'
import type { ReportField } from '@/types/issueReportTypes'
import {
@@ -81,6 +90,8 @@ import {
import ReportIssuePanel from './error/ReportIssuePanel.vue'
const authStore = useFirebaseAuthStore()
const { error } = defineProps<{
error: Omit<ErrorReportData, 'workflow' | 'systemStats' | 'serverLogs'> & {
/**
@@ -123,6 +134,10 @@ const stackTraceField = computed<ReportField>(() => {
}
})
const showContactSupport = async () => {
await useCommandStore().execute('Comfy.ContactSupport')
}
onMounted(async () => {
if (!systemStatsStore.systemStats) {
await systemStatsStore.fetchSystemStats()

View File

@@ -23,75 +23,136 @@
</div>
</template>
<div class="p-4 mt-2 border border-round surface-border shadow-1">
<div class="flex flex-row gap-3 mb-2">
<div v-for="field in fields" :key="field.value">
<FormField
v-if="field.optIn"
v-slot="$field"
:name="field.value"
class="flex space-x-1"
<div class="flex flex-col gap-6">
<FormField
v-slot="$field"
name="contactInfo"
:initial-value="authStore.currentUser?.email"
>
<div class="self-stretch inline-flex justify-start items-center">
<label for="contactInfo" class="pb-2 pt-0 opacity-80">{{
$t('issueReport.email')
}}</label>
</div>
<InputText
id="contactInfo"
v-bind="$field"
class="w-full"
:placeholder="$t('issueReport.provideEmail')"
/>
<Message
v-if="$field?.error && $field.touched && $field.value !== ''"
severity="error"
size="small"
variant="simple"
>
<Checkbox
{{ t('issueReport.validation.invalidEmail') }}
</Message>
</FormField>
<FormField v-slot="$field" name="helpType">
<div class="flex flex-col gap-2">
<div
class="self-stretch inline-flex justify-start items-center gap-2.5"
>
<label for="helpType" class="pb-2 pt-0 opacity-80">{{
$t('issueReport.whatDoYouNeedHelpWith')
}}</label>
</div>
<Dropdown
v-bind="$field"
v-model="selection"
:input-id="field.value"
:value="field.value"
v-model="$field.value"
:options="helpTypes"
option-label="label"
option-value="value"
:placeholder="$t('issueReport.selectIssue')"
class="w-full"
/>
<label :for="field.value">{{ field.label }}</label>
<Message
v-if="$field?.error"
severity="error"
size="small"
variant="simple"
>
{{ t('issueReport.validation.selectIssueType') }}
</Message>
</div>
</FormField>
<div class="flex flex-col gap-2">
<div
class="self-stretch inline-flex justify-start items-center gap-2.5"
>
<span class="pb-2 pt-0 opacity-80">{{
$t('issueReport.whatCanWeInclude')
}}</span>
</div>
<div class="flex flex-row gap-3">
<div v-for="field in fields" :key="field.value">
<FormField
v-if="field.optIn"
v-slot="$field"
:name="field.value"
class="flex space-x-1"
>
<Checkbox
v-bind="$field"
v-model="selection"
:input-id="field.value"
:value="field.value"
/>
<label :for="field.value">{{ field.label }}</label>
</FormField>
</div>
</div>
</div>
<div class="flex flex-col gap-2">
<FormField v-slot="$field" name="details">
<div
class="self-stretch inline-flex justify-start items-center gap-2.5"
>
<label for="details" class="pb-2 pt-0 opacity-80">{{
$t('issueReport.describeTheProblem')
}}</label>
</div>
<Textarea
v-bind="$field"
id="details"
class="w-full"
rows="5"
:placeholder="$t('issueReport.provideAdditionalDetails')"
:aria-label="$t('issueReport.provideAdditionalDetails')"
/>
<Message
v-if="$field?.error && $field.touched && $field.value"
severity="error"
size="small"
variant="simple"
>
{{ t('issueReport.validation.maxLength') }}
</Message>
</FormField>
</div>
</div>
<FormField v-slot="$field" class="mb-4" name="details">
<Textarea
v-bind="$field"
class="w-full"
rows="5"
:placeholder="$t('issueReport.provideAdditionalDetails')"
:aria-label="$t('issueReport.provideAdditionalDetails')"
/>
<Message
v-if="$field?.error && $field.touched && $field.value"
severity="error"
size="small"
variant="simple"
>
{{ t('issueReport.validation.maxLength') }}
</Message>
</FormField>
<FormField v-slot="$field" name="contactInfo">
<InputText
v-bind="$field"
class="w-full"
:placeholder="$t('issueReport.provideEmail')"
/>
<Message
v-if="$field?.error && $field.touched && $field.value !== ''"
severity="error"
size="small"
variant="simple"
>
{{ t('issueReport.validation.invalidEmail') }}
</Message>
</FormField>
<div class="flex flex-row gap-3 mt-2">
<div v-for="checkbox in contactCheckboxes" :key="checkbox.value">
<FormField
v-slot="$field"
:name="checkbox.value"
class="flex space-x-1"
>
<Checkbox
v-bind="$field"
v-model="contactPrefs"
:input-id="checkbox.value"
:value="checkbox.value"
:disabled="
$form.contactInfo?.error || !$form.contactInfo?.value
"
/>
<label :for="checkbox.value">{{ checkbox.label }}</label>
</FormField>
<div class="flex flex-col gap-3 mt-2">
<div v-for="checkbox in contactCheckboxes" :key="checkbox.value">
<FormField
v-slot="$field"
:name="checkbox.value"
class="flex space-x-1"
>
<Checkbox
v-bind="$field"
v-model="contactPrefs"
:input-id="checkbox.value"
:value="checkbox.value"
:disabled="
$form.contactInfo?.error || !$form.contactInfo?.value
"
/>
<label :for="checkbox.value">{{ checkbox.label }}</label>
</FormField>
</div>
</div>
</div>
</div>
@@ -108,6 +169,7 @@ import _ from 'lodash'
import cloneDeep from 'lodash/cloneDeep'
import Button from 'primevue/button'
import Checkbox from 'primevue/checkbox'
import Dropdown from 'primevue/dropdown'
import InputText from 'primevue/inputtext'
import Message from 'primevue/message'
import Panel from 'primevue/panel'
@@ -122,14 +184,16 @@ import {
} from '@/schemas/issueReportSchema'
import { api } from '@/scripts/api'
import { app } from '@/scripts/app'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import type {
DefaultField,
IssueReportPanelProps,
ReportField
} from '@/types/issueReportTypes'
import { isElectron } from '@/utils/envUtil'
import { generateUUID } from '@/utils/formatUtil'
const ISSUE_NAME = 'User reported issue'
const DEFAULT_ISSUE_NAME = 'User reported issue'
const props = defineProps<IssueReportPanelProps>()
const { defaultFields = ['Workflow', 'Logs', 'SystemStats', 'Settings'] } =
@@ -137,6 +201,7 @@ const { defaultFields = ['Workflow', 'Logs', 'SystemStats', 'Settings'] } =
const { t } = useI18n()
const toast = useToast()
const authStore = useFirebaseAuthStore()
const selection = ref<string[]>([])
const contactPrefs = ref<string[]>([])
@@ -147,6 +212,20 @@ const contactCheckboxes = [
{ label: t('issueReport.notifyResolve'), value: 'notifyOnResolution' }
]
const helpTypes = [
{
label: t('issueReport.helpTypes.billingPayments'),
value: 'billingPayments'
},
{
label: t('issueReport.helpTypes.loginAccessIssues'),
value: 'loginAccessIssues'
},
{ label: t('issueReport.helpTypes.giveFeedback'), value: 'giveFeedback' },
{ label: t('issueReport.helpTypes.bugReport'), value: 'bugReport' },
{ label: t('issueReport.helpTypes.somethingElse'), value: 'somethingElse' }
]
const defaultFieldsConfig: ReportField[] = [
{
label: t('issueReport.systemStats'),
@@ -213,6 +292,7 @@ const createCaptureContext = async (
level: 'error',
tags: {
errorType: props.errorType,
helpType: formData.helpType,
followUp: formData.contactInfo ? formData.followUp : false,
notifyOnResolution: formData.contactInfo
? formData.notifyOnResolution
@@ -227,11 +307,24 @@ const createCaptureContext = async (
}
}
const generateUniqueTicketId = (type: string) => `${type}-${generateUUID()}`
const submit = async (event: FormSubmitEvent) => {
if (event.valid) {
try {
const captureContext = await createCaptureContext(event.values)
captureMessage(ISSUE_NAME, captureContext)
// If it's billing or access issue, generate unique id to be used by customer service ticketing
const isValidContactInfo = event.values.contactInfo?.length
const isCustomerServiceIssue =
isValidContactInfo &&
['billingPayments', 'loginAccessIssues'].includes(
event.values.helpType || ''
)
const issueName = isCustomerServiceIssue
? `ticket-${generateUniqueTicketId(event.values.helpType || '')}`
: DEFAULT_ISSUE_NAME
captureMessage(issueName, captureContext)
submitted.value = true
toast.add({
severity: 'success',

View File

@@ -1,5 +1,6 @@
import { Form } from '@primevue/forms'
import { mount } from '@vue/test-utils'
import { createPinia, setActivePinia } from 'pinia'
import Checkbox from 'primevue/checkbox'
import PrimeVue from 'primevue/config'
import InputText from 'primevue/inputtext'
@@ -65,7 +66,12 @@ vi.mock('@/scripts/api', () => ({
api: {
getLogs: vi.fn().mockResolvedValue('mock logs'),
getSystemStats: vi.fn().mockResolvedValue('mock stats'),
getSettings: vi.fn().mockResolvedValue('mock settings')
getSettings: vi.fn().mockResolvedValue('mock settings'),
fetchApi: vi.fn().mockResolvedValue({
json: vi.fn().mockResolvedValue({}),
text: vi.fn().mockResolvedValue('')
}),
apiURL: vi.fn().mockReturnValue('https://test.com')
}
}))
@@ -139,12 +145,14 @@ vi.mock('@primevue/forms', () => ({
describe('ReportIssuePanel', () => {
beforeEach(() => {
vi.clearAllMocks()
const pinia = createPinia()
setActivePinia(pinia)
})
const mountComponent = (props: IssueReportPanelProps, options = {}): any => {
return mount(ReportIssuePanel, {
global: {
plugins: [PrimeVue, i18n],
plugins: [PrimeVue, i18n, createPinia()],
directives: { tooltip: Tooltip }
},
props,

View File

@@ -134,7 +134,6 @@ const dialogService = useDialogService()
const authStore = useFirebaseAuthStore()
const loading = computed(() => authStore.loading)
// Format balance from micros to dollars
const formattedBalance = computed(() => {
if (!authStore.balance) return '0.00'
return formatMetronomeCurrency(authStore.balance.amount_micros, 'usd')
@@ -162,11 +161,11 @@ const handleCreditsHistoryClick = async () => {
const handleMessageSupport = () => {
dialogService.showIssueReportDialog({
title: t('credits.messageSupport'),
subtitle: t('issueReport.feedbackTitle'),
title: t('issueReport.contactSupportTitle'),
subtitle: t('issueReport.contactSupportDescription'),
panelProps: {
errorType: 'BillingSupport',
defaultFields: ['SystemStats', 'Settings']
defaultFields: ['Workflow', 'Logs', 'SystemStats', 'Settings']
}
})
}

View File

@@ -579,6 +579,22 @@ export function useCoreCommands(): ComfyCommand[] {
})
}
},
{
id: 'Comfy.ContactSupport',
icon: 'pi pi-question',
label: 'Contact Support',
versionAdded: '1.17.8',
function: () => {
dialogService.showIssueReportDialog({
title: t('issueReport.contactSupportTitle'),
subtitle: t('issueReport.contactSupportDescription'),
panelProps: {
errorType: 'ContactSupport',
defaultFields: ['Workflow', 'Logs', 'SystemStats', 'Settings']
}
})
}
},
{
id: 'Comfy.Help.OpenComfyUIForum',
icon: 'pi pi-comments',

View File

@@ -23,5 +23,8 @@ export const CORE_MENU_COMMANDS = [
'Comfy.Help.OpenComfyUIForum'
]
],
[['Help'], ['Comfy.Help.AboutComfyUI', 'Comfy.Feedback']]
[
['Help'],
['Comfy.Help.AboutComfyUI', 'Comfy.Feedback', 'Comfy.ContactSupport']
]
]

View File

@@ -83,6 +83,9 @@
"Comfy_ClearWorkflow": {
"label": "Clear Workflow"
},
"Comfy_ContactSupport": {
"label": "Contact Support"
},
"Comfy_DuplicateWorkflow": {
"label": "Duplicate Current Workflow"
},

View File

@@ -181,9 +181,24 @@
"helpFix": "Help Fix This",
"rating": "Rating",
"feedbackTitle": "Help us improve ComfyUI by providing feedback",
"contactSupportTitle": "Contact Support",
"contactSupportDescription": "Please fill in the form below with your report",
"selectIssue": "Select the issue",
"whatDoYouNeedHelpWith": "What do you need help with?",
"whatCanWeInclude": "Specify what to include in the report",
"describeTheProblem": "Describe the problem",
"email": "Email",
"helpTypes": {
"billingPayments": "Billing / Payments",
"loginAccessIssues": "Login / Access Issues",
"giveFeedback": "Give Feedback",
"bugReport": "Bug Report",
"somethingElse": "Something Else"
},
"validation": {
"maxLength": "Message too long",
"invalidEmail": "Please enter a valid email address"
"invalidEmail": "Please enter a valid email address",
"selectIssueType": "Please select an issue type"
}
},
"color": {
@@ -631,6 +646,7 @@
"Zoom Out": "Zoom Out",
"Clear Pending Tasks": "Clear Pending Tasks",
"Clear Workflow": "Clear Workflow",
"Contact Support": "Contact Support",
"Duplicate Current Workflow": "Duplicate Current Workflow",
"Export": "Export",
"Export (API)": "Export (API)",

View File

@@ -83,6 +83,9 @@
"Comfy_ClearWorkflow": {
"label": "Borrar flujo de trabajo"
},
"Comfy_ContactSupport": {
"label": "Contactar soporte"
},
"Comfy_DuplicateWorkflow": {
"label": "Duplicar flujo de trabajo actual"
},

View File

@@ -431,19 +431,34 @@
},
"issueReport": {
"contactFollowUp": "Contáctame para seguimiento",
"contactSupportDescription": "Por favor, complete el siguiente formulario con su reporte",
"contactSupportTitle": "Contactar Soporte",
"describeTheProblem": "Describa el problema",
"email": "Correo electrónico",
"feedbackTitle": "Ayúdanos a mejorar ComfyUI proporcionando comentarios",
"helpFix": "Ayuda a Solucionar Esto",
"helpTypes": {
"billingPayments": "Facturación / Pagos",
"bugReport": "Reporte de error",
"giveFeedback": "Enviar comentarios",
"loginAccessIssues": "Problemas de inicio de sesión / acceso",
"somethingElse": "Otro"
},
"notifyResolve": "Notifícame cuando se resuelva",
"provideAdditionalDetails": "Proporciona detalles adicionales (opcional)",
"provideEmail": "Danos tu correo electrónico (opcional)",
"rating": "Calificación",
"selectIssue": "Seleccione el problema",
"stackTrace": "Rastreo de Pila",
"submitErrorReport": "Enviar Reporte de Error (Opcional)",
"systemStats": "Estadísticas del Sistema",
"validation": {
"invalidEmail": "Por favor ingresa una dirección de correo electrónico válida",
"maxLength": "Mensaje demasiado largo"
}
"maxLength": "Mensaje demasiado largo",
"selectIssueType": "Por favor, seleccione un tipo de problema"
},
"whatCanWeInclude": "Especifique qué incluir en el reporte",
"whatDoYouNeedHelpWith": "¿Con qué necesita ayuda?"
},
"load3d": {
"applyingTexture": "Aplicando textura...",
@@ -616,6 +631,7 @@
"ComfyUI Docs": "Documentos de ComfyUI",
"ComfyUI Forum": "Foro de ComfyUI",
"ComfyUI Issues": "Problemas de ComfyUI",
"Contact Support": "Contactar soporte",
"Convert selected nodes to group node": "Convertir nodos seleccionados en nodo de grupo",
"Custom Nodes Manager": "Gestor de nodos personalizados",
"Delete Selected Items": "Eliminar elementos seleccionados",

View File

@@ -83,6 +83,9 @@
"Comfy_ClearWorkflow": {
"label": "Effacer le flux de travail"
},
"Comfy_ContactSupport": {
"label": "Contacter le support"
},
"Comfy_DuplicateWorkflow": {
"label": "Dupliquer le flux de travail actuel"
},

View File

@@ -431,19 +431,34 @@
},
"issueReport": {
"contactFollowUp": "Contactez-moi pour un suivi",
"contactSupportDescription": "Veuillez remplir le formulaire ci-dessous avec votre signalement",
"contactSupportTitle": "Contacter le support",
"describeTheProblem": "Décrivez le problème",
"email": "E-mail",
"feedbackTitle": "Aidez-nous à améliorer ComfyUI en fournissant des commentaires",
"helpFix": "Aidez à résoudre cela",
"helpTypes": {
"billingPayments": "Facturation / Paiements",
"bugReport": "Signaler un bug",
"giveFeedback": "Donner un avis",
"loginAccessIssues": "Problèmes de connexion / d'accès",
"somethingElse": "Autre chose"
},
"notifyResolve": "Prévenez-moi lorsque résolu",
"provideAdditionalDetails": "Fournir des détails supplémentaires (facultatif)",
"provideEmail": "Donnez-nous votre email (Facultatif)",
"rating": "Évaluation",
"selectIssue": "Sélectionnez le problème",
"stackTrace": "Trace de la pile",
"submitErrorReport": "Soumettre un rapport d'erreur (Facultatif)",
"systemStats": "Statistiques du système",
"validation": {
"invalidEmail": "Veuillez entrer une adresse e-mail valide",
"maxLength": "Message trop long"
}
"maxLength": "Message trop long",
"selectIssueType": "Veuillez sélectionner un type de problème"
},
"whatCanWeInclude": "Précisez ce qu'il faut inclure dans le rapport",
"whatDoYouNeedHelpWith": "Avec quoi avez-vous besoin d'aide ?"
},
"load3d": {
"applyingTexture": "Application de la texture...",
@@ -616,6 +631,7 @@
"ComfyUI Docs": "Docs de ComfyUI",
"ComfyUI Forum": "Forum ComfyUI",
"ComfyUI Issues": "Problèmes de ComfyUI",
"Contact Support": "Contacter le support",
"Convert selected nodes to group node": "Convertir les nœuds sélectionnés en nœud de groupe",
"Custom Nodes Manager": "Gestionnaire de Nœuds Personnalisés",
"Delete Selected Items": "Supprimer les éléments sélectionnés",

View File

@@ -83,6 +83,9 @@
"Comfy_ClearWorkflow": {
"label": "ワークフローをクリア"
},
"Comfy_ContactSupport": {
"label": "サポートに連絡"
},
"Comfy_DuplicateWorkflow": {
"label": "現在のワークフローを複製"
},

View File

@@ -431,19 +431,34 @@
},
"issueReport": {
"contactFollowUp": "フォローアップのために私に連絡する",
"contactSupportDescription": "下記のフォームにご報告内容をご記入ください",
"contactSupportTitle": "サポートに連絡",
"describeTheProblem": "問題の内容を記述してください",
"email": "メールアドレス",
"feedbackTitle": "フィードバックを提供してComfyUIの改善にご協力ください",
"helpFix": "これを修正するのを助ける",
"helpTypes": {
"billingPayments": "請求/支払い",
"bugReport": "バグ報告",
"giveFeedback": "フィードバックを送る",
"loginAccessIssues": "ログイン/アクセスの問題",
"somethingElse": "その他"
},
"notifyResolve": "解決したときに通知する",
"provideAdditionalDetails": "追加の詳細を提供する(オプション)",
"provideEmail": "あなたのメールアドレスを教えてください(オプション)",
"rating": "評価",
"selectIssue": "問題を選択してください",
"stackTrace": "スタックトレース",
"submitErrorReport": "エラーレポートを提出する(オプション)",
"systemStats": "システム統計",
"validation": {
"invalidEmail": "有効なメールアドレスを入力してください",
"maxLength": "メッセージが長すぎます"
}
"maxLength": "メッセージが長すぎます",
"selectIssueType": "問題の種類を選択してください"
},
"whatCanWeInclude": "レポートに含める内容を指定してください",
"whatDoYouNeedHelpWith": "どのようなサポートが必要ですか?"
},
"load3d": {
"applyingTexture": "テクスチャを適用中...",
@@ -616,6 +631,7 @@
"ComfyUI Docs": "ComfyUIのドキュメント",
"ComfyUI Forum": "ComfyUI フォーラム",
"ComfyUI Issues": "ComfyUIの問題",
"Contact Support": "サポートに連絡",
"Convert selected nodes to group node": "選択したノードをグループノードに変換",
"Custom Nodes Manager": "カスタムノードマネージャ",
"Delete Selected Items": "選択したアイテムを削除",

View File

@@ -83,6 +83,9 @@
"Comfy_ClearWorkflow": {
"label": "워크플로 지우기"
},
"Comfy_ContactSupport": {
"label": "지원팀에 문의하기"
},
"Comfy_DuplicateWorkflow": {
"label": "현재 워크플로우 복제"
},

View File

@@ -431,19 +431,34 @@
},
"issueReport": {
"contactFollowUp": "추적 조사를 위해 연락해 주세요",
"contactSupportDescription": "아래 양식에 보고 내용을 작성해 주세요",
"contactSupportTitle": "지원팀에 문의하기",
"describeTheProblem": "문제를 설명해 주세요",
"email": "이메일",
"feedbackTitle": "피드백을 제공함으로써 ComfyUI를 개선하는 데 도움을 주십시오",
"helpFix": "이 문제 해결에 도움을 주세요",
"helpTypes": {
"billingPayments": "결제 / 지불",
"bugReport": "버그 신고",
"giveFeedback": "피드백 제공",
"loginAccessIssues": "로그인 / 접근 문제",
"somethingElse": "기타"
},
"notifyResolve": "해결되었을 때 알려주세요",
"provideAdditionalDetails": "추가 세부 사항 제공 (선택 사항)",
"provideEmail": "이메일을 알려주세요 (선택 사항)",
"rating": "평가",
"selectIssue": "문제를 선택하세요",
"stackTrace": "스택 추적",
"submitErrorReport": "오류 보고서 제출 (선택 사항)",
"systemStats": "시스템 통계",
"validation": {
"invalidEmail": "유효한 이메일 주소를 입력해 주세요",
"maxLength": "메시지가 너무 깁니다"
}
"maxLength": "메시지가 너무 깁니다",
"selectIssueType": "문제 유형을 선택해 주세요"
},
"whatCanWeInclude": "보고서에 포함할 내용을 지정하세요",
"whatDoYouNeedHelpWith": "어떤 도움이 필요하신가요?"
},
"load3d": {
"applyingTexture": "텍스처 적용 중...",
@@ -616,6 +631,7 @@
"ComfyUI Docs": "ComfyUI 문서",
"ComfyUI Forum": "ComfyUI 포럼",
"ComfyUI Issues": "ComfyUI 이슈 페이지",
"Contact Support": "고객 지원 문의",
"Convert selected nodes to group node": "선택한 노드를 그룹 노드로 변환",
"Custom Nodes Manager": "사용자 정의 노드 관리자",
"Delete Selected Items": "선택한 항목 삭제",

View File

@@ -83,6 +83,9 @@
"Comfy_ClearWorkflow": {
"label": "Очистить рабочий процесс"
},
"Comfy_ContactSupport": {
"label": "Связаться с поддержкой"
},
"Comfy_DuplicateWorkflow": {
"label": "Дублировать текущий рабочий процесс"
},

View File

@@ -431,19 +431,34 @@
},
"issueReport": {
"contactFollowUp": "Свяжитесь со мной для уточнения",
"contactSupportDescription": "Пожалуйста, заполните форму ниже для отправки вашего отчёта",
"contactSupportTitle": "Связаться с поддержкой",
"describeTheProblem": "Опишите проблему",
"email": "Электронная почта",
"feedbackTitle": "Помогите нам улучшить ComfyUI, оставив отзыв",
"helpFix": "Помочь исправить это",
"helpTypes": {
"billingPayments": "Оплата / Платежи",
"bugReport": "Сообщить об ошибке",
"giveFeedback": "Оставить отзыв",
"loginAccessIssues": "Проблемы со входом / доступом",
"somethingElse": "Другое"
},
"notifyResolve": "Уведомить меня, когда проблема будет решена",
"provideAdditionalDetails": "Предоставьте дополнительные сведения (необязательно)",
"provideEmail": "Укажите вашу электронную почту (необязательно)",
"rating": "Рейтинг",
"selectIssue": "Выберите проблему",
"stackTrace": "Трассировка стека",
"submitErrorReport": "Отправить отчёт об ошибке (необязательно)",
"systemStats": "Статистика системы",
"validation": {
"invalidEmail": "Пожалуйста, введите действительный адрес электронной почты",
"maxLength": "Сообщение слишком длинное"
}
"maxLength": "Сообщение слишком длинное",
"selectIssueType": "Пожалуйста, выберите тип проблемы"
},
"whatCanWeInclude": "Уточните, что включить в отчёт",
"whatDoYouNeedHelpWith": "С чем вам нужна помощь?"
},
"load3d": {
"applyingTexture": "Применение текстуры...",
@@ -616,6 +631,7 @@
"ComfyUI Docs": "Документация ComfyUI",
"ComfyUI Forum": "Форум ComfyUI",
"ComfyUI Issues": "Проблемы ComfyUI",
"Contact Support": "Связаться с поддержкой",
"Convert selected nodes to group node": "Преобразовать выбранные ноды в групповую ноду",
"Custom Nodes Manager": "Менеджер Пользовательских Узлов",
"Delete Selected Items": "Удалить выбранные элементы",

View File

@@ -83,6 +83,9 @@
"Comfy_ClearWorkflow": {
"label": "清除工作流"
},
"Comfy_ContactSupport": {
"label": "联系支持"
},
"Comfy_DuplicateWorkflow": {
"label": "复制当前工作流"
},

View File

@@ -431,19 +431,34 @@
},
"issueReport": {
"contactFollowUp": "跟进联系我",
"contactSupportDescription": "请填写下方表格提交您的报告",
"contactSupportTitle": "联系支持",
"describeTheProblem": "描述问题",
"email": "电子邮箱",
"feedbackTitle": "通过提供反馈帮助我们改进ComfyUI",
"helpFix": "帮助修复这个",
"helpTypes": {
"billingPayments": "账单 / 支付",
"bugReport": "错误报告",
"giveFeedback": "提交反馈",
"loginAccessIssues": "登录 / 访问问题",
"somethingElse": "其他"
},
"notifyResolve": "解决时通知我",
"provideAdditionalDetails": "提供额外的详细信息(可选)",
"provideEmail": "提供您的电子邮件(可选)",
"rating": "评分",
"selectIssue": "选择问题",
"stackTrace": "堆栈跟踪",
"submitErrorReport": "提交错误报告(可选)",
"systemStats": "系统状态",
"validation": {
"invalidEmail": "请输入有效的电子邮件地址",
"maxLength": "消息过长"
}
"maxLength": "消息过长",
"selectIssueType": "请选择一个问题类型"
},
"whatCanWeInclude": "请说明报告中需要包含的内容",
"whatDoYouNeedHelpWith": "您需要什么帮助?"
},
"load3d": {
"applyingTexture": "应用纹理中...",
@@ -616,6 +631,7 @@
"ComfyUI Docs": "ComfyUI 文档",
"ComfyUI Forum": "ComfyUI 论坛",
"ComfyUI Issues": "ComfyUI 问题",
"Contact Support": "联系支持",
"Convert selected nodes to group node": "将选中节点转换为组节点",
"Custom Nodes Manager": "自定义节点管理器",
"Delete Selected Items": "删除选定的项目",

View File

@@ -4,10 +4,15 @@ const checkboxField = z.boolean().optional()
export const issueReportSchema = z
.object({
contactInfo: z.string().email().max(320).optional().or(z.literal('')),
details: z.string().max(5_000).optional()
details: z.string().max(5_000).optional(),
helpType: z.string().optional()
})
.catchall(checkboxField)
.refine((data) => Object.values(data).some((value) => value), {
path: ['details']
path: ['details', 'helpType']
})
.refine((data) => data.helpType !== undefined && data.helpType !== '', {
message: 'Help type is required',
path: ['helpType']
})
export type IssueReportFormData = z.infer<typeof issueReportSchema>

View File

@@ -87,7 +87,7 @@ export const useDialogService = () => {
error: {
exceptionType: executionError.exception_type,
exceptionMessage: executionError.exception_message,
nodeId: executionError.node_id,
nodeId: executionError.node_id?.toString(),
nodeType: executionError.node_type,
traceback: executionError.traceback.join('\n'),
reportType: 'graphExecutionError'