mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-26 17:54:14 +00:00
## Summary Enhances the error panel with node-specific views: single-node selection shows errors grouped by message in compact mode, container nodes (subgraph/group) expose child errors via a badge and "See Error" button, and a floating ErrorOverlay appears after execution failure with a deduplicated summary and quick navigation to the errors tab. ## Changes - **Consolidate error tab**: Remove `TabError.vue`; merge all error display into `TabErrors.vue` and drop the separate `error` tab type from `rightSidePanelStore` - **Selection-aware grouping**: Single-node selection regroups errors by message (not `class_type`) and renders `ErrorNodeCard` in compact mode - **Container node support**: Detect child-node errors in subgraph/group nodes via execution ID prefix matching; show error badge and "See Error" button in `SectionWidgets` - **ErrorOverlay**: New floating card shown after execution failure with deduplicated error messages, "Dismiss" and "See Errors" actions; `isErrorOverlayOpen` / `showErrorOverlay` / `dismissErrorOverlay` added to `executionStore` - **Refactor**: Centralize error ID collection in `executionStore` (`allErrorExecutionIds`, `hasInternalErrorForNode`); split `errorGroups` into `allErrorGroups` (unfiltered) and `tabErrorGroups` (selection-filtered); move `ErrorOverlay` business logic into `useErrorGroups` ## Review Focus - `useErrorGroups.ts`: split into `allErrorGroups` / `tabErrorGroups` and the new `filterBySelection` parameter flow - `executionStore.ts`: `hasInternalErrorForNode` helper and `allErrorExecutionIds` computed - `ErrorOverlay.vue`: integration with `executionStore` overlay state and `useErrorGroups` ## Screenshots <img width="853" height="461" alt="image" src="https://github.com/user-attachments/assets/a49ab620-4209-4ae7-b547-fba13da0c633" /> <img width="854" height="203" alt="image" src="https://github.com/user-attachments/assets/c119da54-cd78-4e7a-8b7a-456cfd348f1d" /> <img width="497" height="361" alt="image" src="https://github.com/user-attachments/assets/74b16161-cf45-454b-ae60-24922fe36931" /> --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: github-actions <github-actions@github.com>
93 lines
2.7 KiB
TypeScript
93 lines
2.7 KiB
TypeScript
import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'
|
|
import type { NodeError, PromptError } from '@/schemas/apiSchema'
|
|
|
|
/**
|
|
* The standard prompt validation response shape (`{ error, node_errors }`).
|
|
* In cloud, this is embedded as JSON inside `execution_error.exception_message`
|
|
* because prompts are queued asynchronously and errors arrive via WebSocket
|
|
* rather than as direct HTTP responses.
|
|
*/
|
|
interface CloudValidationError {
|
|
error?: { type?: string; message?: string; details?: string } | string
|
|
node_errors?: Record<NodeId, NodeError>
|
|
}
|
|
|
|
export function isCloudValidationError(
|
|
value: unknown
|
|
): value is CloudValidationError {
|
|
return (
|
|
value !== null &&
|
|
typeof value === 'object' &&
|
|
('error' in value || 'node_errors' in value)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Extracts a prompt validation response embedded in an exception message string.
|
|
*
|
|
* Cloud example `exception_message`:
|
|
* "Failed to send prompt request: ... 400: {\"error\":{...},\"node_errors\":{...}}"
|
|
*
|
|
* This function finds the first '{' and parses the trailing JSON.
|
|
*/
|
|
export function tryExtractValidationError(
|
|
exceptionMessage: string
|
|
): CloudValidationError | null {
|
|
const jsonStart = exceptionMessage.indexOf('{')
|
|
const jsonEnd = exceptionMessage.lastIndexOf('}')
|
|
if (jsonStart === -1 || jsonEnd === -1) return null
|
|
|
|
try {
|
|
const parsed: unknown = JSON.parse(
|
|
exceptionMessage.substring(jsonStart, jsonEnd + 1)
|
|
)
|
|
return isCloudValidationError(parsed) ? parsed : null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
type CloudValidationResult =
|
|
| { kind: 'nodeErrors'; nodeErrors: Record<NodeId, NodeError> }
|
|
| { kind: 'promptError'; promptError: PromptError }
|
|
|
|
/**
|
|
* Classifies an embedded cloud validation error from `exception_message`
|
|
* as either node-level errors or a prompt-level error.
|
|
*
|
|
* Returns `null` if the message does not contain a recognizable validation error.
|
|
*/
|
|
export function classifyCloudValidationError(
|
|
exceptionMessage: string
|
|
): CloudValidationResult | null {
|
|
const extracted = tryExtractValidationError(exceptionMessage)
|
|
if (!extracted) return null
|
|
|
|
const { error, node_errors } = extracted
|
|
const hasNodeErrors = node_errors && Object.keys(node_errors).length > 0
|
|
|
|
if (hasNodeErrors) {
|
|
return { kind: 'nodeErrors', nodeErrors: node_errors }
|
|
}
|
|
|
|
if (error && typeof error === 'object') {
|
|
return {
|
|
kind: 'promptError',
|
|
promptError: {
|
|
type: error.type ?? 'error',
|
|
message: error.message ?? '',
|
|
details: error.details ?? ''
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof error === 'string') {
|
|
return {
|
|
kind: 'promptError',
|
|
promptError: { type: 'error', message: error, details: '' }
|
|
}
|
|
}
|
|
|
|
return null
|
|
}
|