Show error list
This commit is contained in:
@@ -22,6 +22,8 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
private _unsubscribe: Unsubscriber;
|
private _unsubscribe: Unsubscriber;
|
||||||
isExportingSVG: boolean = false;
|
isExportingSVG: boolean = false;
|
||||||
activeErrors?: ComfyGraphErrors = null;
|
activeErrors?: ComfyGraphErrors = null;
|
||||||
|
blinkError: ComfyGraphErrorLocation | null = null;
|
||||||
|
blinkErrorTime: number = 0;
|
||||||
|
|
||||||
get comfyGraph(): ComfyGraph | null {
|
get comfyGraph(): ComfyGraph | null {
|
||||||
return this.graph as ComfyGraph;
|
return this.graph as ComfyGraph;
|
||||||
@@ -96,8 +98,13 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
const isRunningNode = node.id == state.runningNodeID
|
const isRunningNode = node.id == state.runningNodeID
|
||||||
const nodeErrors = this.activeErrors?.errorsByID[node.id];
|
const nodeErrors = this.activeErrors?.errorsByID[node.id];
|
||||||
|
|
||||||
|
if (this.blinkErrorTime > 0) {
|
||||||
|
this.blinkErrorTime -= this.graph.elapsed_time;
|
||||||
|
}
|
||||||
|
|
||||||
let color = null;
|
let color = null;
|
||||||
let thickness = 1;
|
let thickness = 1;
|
||||||
|
let blink = false;
|
||||||
// if (this._selectedNodes.has(node.id)) {
|
// if (this._selectedNodes.has(node.id)) {
|
||||||
// color = "yellow";
|
// color = "yellow";
|
||||||
// thickness = 5;
|
// thickness = 5;
|
||||||
@@ -111,6 +118,7 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
else if (nodeErrors) {
|
else if (nodeErrors) {
|
||||||
const hasExecutionError = nodeErrors.find(e => e.errorType === "execution");
|
const hasExecutionError = nodeErrors.find(e => e.errorType === "execution");
|
||||||
if (hasExecutionError) {
|
if (hasExecutionError) {
|
||||||
|
blink = true;
|
||||||
color = "#f0f";
|
color = "#f0f";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -119,6 +127,14 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
thickness = 2
|
thickness = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blink) {
|
||||||
|
if (nodeErrors && nodeErrors.includes(this.blinkError) && this.blinkErrorTime > 0) {
|
||||||
|
if ((Math.floor(this.blinkErrorTime / 2)) % 2 === 0) {
|
||||||
|
color = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (color) {
|
if (color) {
|
||||||
this.drawNodeOutline(node, ctx, size, mouseOver, fgColor, bgColor, color, thickness)
|
this.drawNodeOutline(node, ctx, size, mouseOver, fgColor, bgColor, color, thickness)
|
||||||
}
|
}
|
||||||
@@ -139,6 +155,11 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
ctx.strokeStyle = "red";
|
ctx.strokeStyle = "red";
|
||||||
for (const errorLocation of errors) {
|
for (const errorLocation of errors) {
|
||||||
if (errorLocation.input != null) {
|
if (errorLocation.input != null) {
|
||||||
|
if (errorLocation === this.blinkError && this.blinkErrorTime > 0) {
|
||||||
|
if ((Math.floor(this.blinkErrorTime / 2)) % 2 === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
const inputIndex = node.findInputSlotIndexByName(errorLocation.input.name)
|
const inputIndex = node.findInputSlotIndexByName(errorLocation.input.name)
|
||||||
if (inputIndex !== -1) {
|
if (inputIndex !== -1) {
|
||||||
let pos = node.getConnectionPos(true, inputIndex);
|
let pos = node.getConnectionPos(true, inputIndex);
|
||||||
@@ -607,17 +628,29 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
this.jumpToError(0);
|
this.jumpToError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
jumpToError(index: number) {
|
jumpToError(index: number | ComfyGraphErrorLocation) {
|
||||||
if (this.activeErrors == null) {
|
if (this.activeErrors == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = this.activeErrors.errors[index]
|
let error;
|
||||||
|
if (typeof index === "number") {
|
||||||
|
error = this.activeErrors.errors[index]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
error = index;
|
||||||
|
}
|
||||||
|
|
||||||
if (error == null) {
|
if (error == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = this.graph.getNodeByIdRecursive(error.nodeID);
|
const rootGraph = this.graph.getRootGraph()
|
||||||
|
if (rootGraph == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const node = rootGraph.getNodeByIdRecursive(error.nodeID);
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
notify(`Couldn't find node '${error.comfyNodeType}' (${error.nodeID})`, { type: "warning" })
|
notify(`Couldn't find node '${error.comfyNodeType}' (${error.nodeID})`, { type: "warning" })
|
||||||
return
|
return
|
||||||
@@ -637,5 +670,8 @@ export default class ComfyGraphCanvas extends LGraphCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.centerOnNode(node);
|
this.centerOnNode(node);
|
||||||
|
|
||||||
|
this.blinkError = error;
|
||||||
|
this.blinkErrorTime = 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ export default class ComfyApp {
|
|||||||
if (errors && errors.length > 0)
|
if (errors && errors.length > 0)
|
||||||
error = "Error(s) loading builtin templates:\n" + errors.join("\n");
|
error = "Error(s) loading builtin templates:\n" + errors.join("\n");
|
||||||
|
|
||||||
console.log(`Loaded {templates.length} builtin templates.`);
|
console.log(`Loaded ${templates.length} builtin templates.`);
|
||||||
|
|
||||||
return [templates, error]
|
return [templates, error]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -240,6 +240,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
workflowState.setActiveWorkflow(app.lCanvas, workflow.id);
|
workflowState.setActiveWorkflow(app.lCanvas, workflow.id);
|
||||||
|
$uiState.activeError = promptIDWithError;
|
||||||
|
|
||||||
const jumpToError = () => {
|
const jumpToError = () => {
|
||||||
app.resizeCanvas();
|
app.resizeCanvas();
|
||||||
@@ -271,6 +272,7 @@
|
|||||||
function hideError() {
|
function hideError() {
|
||||||
if (app?.lCanvas) {
|
if (app?.lCanvas) {
|
||||||
app.lCanvas.activeErrors = null;
|
app.lCanvas.activeErrors = null;
|
||||||
|
app.lCanvas.blinkError = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
228
src/lib/components/ComfyGraphErrorList.svelte
Normal file
228
src/lib/components/ComfyGraphErrorList.svelte
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { ComfyGraphErrorLocation, ComfyGraphErrors } from "$lib/apiErrors";
|
||||||
|
import type ComfyApp from "./ComfyApp";
|
||||||
|
import Accordion from "./gradio/app/Accordion.svelte";
|
||||||
|
import uiState from '$lib/stores/uiState';
|
||||||
|
import type { ComfyNodeDefInputType } from "$lib/ComfyNodeDef";
|
||||||
|
|
||||||
|
export let app: ComfyApp;
|
||||||
|
export let errors: ComfyGraphErrors;
|
||||||
|
|
||||||
|
function closeList() {
|
||||||
|
app.lCanvas.activeErrors = null;
|
||||||
|
app.lCanvas.blinkError = null;
|
||||||
|
$uiState.activeError = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParentNode(error: ComfyGraphErrorLocation): Subgraph | null {
|
||||||
|
const node = app.lCanvas.graph.getNodeByIdRecursive(error.nodeID);
|
||||||
|
if (node == null || !node.graph._is_subgraph)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return node.graph._subgraph_node
|
||||||
|
}
|
||||||
|
|
||||||
|
function jumpToError(error: ComfyGraphErrorLocation) {
|
||||||
|
app.lCanvas.jumpToError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInputTypeName(type: ComfyNodeDefInputType) {
|
||||||
|
if (Array.isArray(type)) {
|
||||||
|
return `List (${type.length})`
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="error-list">
|
||||||
|
<div class="error-list-header">
|
||||||
|
<button class="error-list-close" on:click={closeList}>✕</button>
|
||||||
|
</div>
|
||||||
|
{#each Object.entries(errors.errorsByID) as [nodeID, nodeErrors]}
|
||||||
|
{@const first = nodeErrors[0]}
|
||||||
|
{@const parent = getParentNode(first)}
|
||||||
|
<div class="error-group">
|
||||||
|
<div class="error-node-details">
|
||||||
|
<span class="error-node-type">{first.comfyNodeType}</span>
|
||||||
|
{#if parent}
|
||||||
|
<span class="error-node-parent">({parent.title})</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="error-entries">
|
||||||
|
{#each nodeErrors as error}
|
||||||
|
{@const isExecutionError = error.errorType === "execution"}
|
||||||
|
<div class="error-entry">
|
||||||
|
<div>
|
||||||
|
<div class="error-details">
|
||||||
|
<button class="jump-to-error" class:execution-error={isExecutionError} on:click={() => jumpToError(error)}><span>⮎</span></button>
|
||||||
|
<div>
|
||||||
|
<span class="error-message" class:execution-error={isExecutionError}>{error.message}</span>
|
||||||
|
{#if error.exceptionType}
|
||||||
|
<span>({error.exceptionType})</span>
|
||||||
|
{:else if error.input}
|
||||||
|
<div class="error-input">
|
||||||
|
<span>Input Name: {error.input.name}</span>
|
||||||
|
{#if error.input.config}
|
||||||
|
<span>Type: {getInputTypeName(error.input.config[0])}</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{#if error.traceback}
|
||||||
|
<div class="error-traceback-wrapper">
|
||||||
|
<Accordion label="Traceback" open={false}>
|
||||||
|
<div class="error-traceback">
|
||||||
|
<div class="error-traceback-contents">
|
||||||
|
{#each error.traceback as line}
|
||||||
|
<div>{line}</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
.error-list {
|
||||||
|
width: 30%;
|
||||||
|
height: 70%;
|
||||||
|
margin: 1.0rem;
|
||||||
|
overflow-y: auto;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
color: #ddd;
|
||||||
|
background: #444;
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-list-header {
|
||||||
|
width: 100%;
|
||||||
|
height: 24px;
|
||||||
|
margin: auto;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
background: #282828;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.error-list-close {
|
||||||
|
margin: auto;
|
||||||
|
padding-right: 6px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-node-details {
|
||||||
|
font-size: 14pt;
|
||||||
|
color: #ddd;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 0.7rem 1.0rem;
|
||||||
|
background: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-node-parent {
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 12pt;
|
||||||
|
font-weight: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-entries:last-child {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-entry {
|
||||||
|
opacity: 100%;
|
||||||
|
border-top: 1px solid #ccc;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: var(--spacing-md);
|
||||||
|
vertical-align: bottom;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
bottom: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: #F66;
|
||||||
|
&.execution-error {
|
||||||
|
color: #E6E;
|
||||||
|
}
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-input {
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jump-to-error {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background: #844;
|
||||||
|
&.execution-error {
|
||||||
|
background: #848;
|
||||||
|
}
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
font-size: 14pt;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
justify-content: center;
|
||||||
|
margin-right: 0.3rem;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(120%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
filter: brightness(80%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-traceback-wrapper {
|
||||||
|
margin-top: 1.0rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 1px solid #888;
|
||||||
|
|
||||||
|
.error-traceback {
|
||||||
|
font-size: 11pt;
|
||||||
|
overflow: auto;
|
||||||
|
white-space: nowrap;
|
||||||
|
background: #333;
|
||||||
|
|
||||||
|
.error-traceback-contents {
|
||||||
|
width: 100%;
|
||||||
|
font-family: monospace;
|
||||||
|
padding: 1.0rem;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,13 +5,15 @@
|
|||||||
import interfaceState from "$lib/stores/interfaceState";
|
import interfaceState from "$lib/stores/interfaceState";
|
||||||
import workflowState from "$lib/stores/workflowState";
|
import workflowState from "$lib/stores/workflowState";
|
||||||
import uiState from '$lib/stores/uiState';
|
import uiState from '$lib/stores/uiState';
|
||||||
|
import ComfyGraphErrorList from "$lib/components/ComfyGraphErrorList.svelte"
|
||||||
|
|
||||||
export let app: ComfyApp;
|
export let app: ComfyApp;
|
||||||
|
|
||||||
let canvas: HTMLCanvasElement;
|
let canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (app?.lCanvas && canvas) {
|
if (app?.lCanvas) {
|
||||||
|
canvas = app.lCanvas.canvas;
|
||||||
app.lCanvas?.setCanvas(canvas)
|
app.lCanvas?.setCanvas(canvas)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -40,6 +42,9 @@
|
|||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#if $uiState.activeError && app?.lCanvas?.activeErrors != null}
|
||||||
|
<ComfyGraphErrorList {app} errors={app.lCanvas.activeErrors} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ function notifyf7(text: string, options: NotifyOptions) {
|
|||||||
function notifyToast(text: string, options: NotifyOptions) {
|
function notifyToast(text: string, options: NotifyOptions) {
|
||||||
const toastOptions: SvelteToastOptions = {
|
const toastOptions: SvelteToastOptions = {
|
||||||
dismissable: options.timeout !== null,
|
dismissable: options.timeout !== null,
|
||||||
duration: options.timeout,
|
duration: options.timeout || 5000,
|
||||||
theme: {},
|
theme: {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user