mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
## Summary - Add `errorMessage` and `executionError` getters to `TaskItemImpl` that extract error info from status messages - Update `useJobErrorReporting` composable to use these getters instead of standalone function - Remove the standalone `extractExecutionError` function This encapsulates error extraction within `TaskItemImpl`, preparing for the Jobs API migration where the underlying data format will change but the getter interface will remain stable. ## Test plan - [x] All existing tests pass - [x] New tests added for `TaskItemImpl.errorMessage` and `TaskItemImpl.executionError` getters - [x] TypeScript, lint, and knip checks pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-7650-refactor-encapsulate-error-extraction-in-TaskItemImpl-getters-2ce6d73d365081caae33dcc7e1e07720) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Christian Byrne <cbyrne@comfy.org>
718 lines
21 KiB
TypeScript
718 lines
21 KiB
TypeScript
import { useSettingStore } from '@/platform/settings/settingStore'
|
|
import { WORKFLOW_ACCEPT_STRING } from '@/platform/workflow/core/types/formats'
|
|
import { type StatusWsMessageStatus } from '@/schemas/apiSchema'
|
|
import { useDialogService } from '@/services/dialogService'
|
|
import { isCloud } from '@/platform/distribution/types'
|
|
import { useTelemetry } from '@/platform/telemetry'
|
|
import { useLitegraphService } from '@/services/litegraphService'
|
|
import { useCommandStore } from '@/stores/commandStore'
|
|
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
|
|
|
import { api } from './api'
|
|
import { ComfyApp, app } from './app'
|
|
import { ComfyDialog as _ComfyDialog } from './ui/dialog'
|
|
import { ComfySettingsDialog } from './ui/settings'
|
|
import { toggleSwitch } from './ui/toggleSwitch'
|
|
|
|
export const ComfyDialog = _ComfyDialog
|
|
|
|
type Position2D = {
|
|
x: number
|
|
y: number
|
|
}
|
|
|
|
type Props = {
|
|
parent?: HTMLElement
|
|
$?: (el: HTMLElement) => void
|
|
dataset?: DOMStringMap
|
|
style?: Partial<CSSStyleDeclaration>
|
|
for?: string
|
|
textContent?: string
|
|
[key: string]: any
|
|
}
|
|
|
|
type Children = Element[] | Element | string | string[]
|
|
|
|
/**
|
|
* @deprecated Legacy queue item structure from old history API.
|
|
* Will be removed when ComfyList is migrated to Jobs API.
|
|
*/
|
|
interface LegacyQueueItem {
|
|
prompt: [unknown, string, unknown, { extra_pnginfo: { workflow: unknown } }]
|
|
outputs?: Record<string, unknown>
|
|
meta?: Record<string, { display_node?: string }>
|
|
remove?: { name: string; cb: () => Promise<void> | void }
|
|
}
|
|
|
|
type ElementType<K extends string> = K extends keyof HTMLElementTagNameMap
|
|
? HTMLElementTagNameMap[K]
|
|
: HTMLElement
|
|
|
|
export function $el<TTag extends string>(
|
|
tag: TTag,
|
|
propsOrChildren?: Children | Props,
|
|
children?: Children
|
|
): ElementType<TTag> {
|
|
const split = tag.split('.')
|
|
const element = document.createElement(split.shift() as string)
|
|
if (split.length > 0) {
|
|
element.classList.add(...split)
|
|
}
|
|
|
|
if (propsOrChildren) {
|
|
if (typeof propsOrChildren === 'string') {
|
|
propsOrChildren = { textContent: propsOrChildren }
|
|
} else if (propsOrChildren instanceof Element) {
|
|
propsOrChildren = [propsOrChildren]
|
|
}
|
|
if (Array.isArray(propsOrChildren)) {
|
|
element.append(...propsOrChildren)
|
|
} else {
|
|
const {
|
|
parent,
|
|
$: cb,
|
|
dataset,
|
|
style,
|
|
...rest
|
|
} = propsOrChildren as Props
|
|
|
|
if (rest.for) {
|
|
element.setAttribute('for', rest.for)
|
|
}
|
|
|
|
if (style) {
|
|
Object.assign(element.style, style)
|
|
}
|
|
|
|
if (dataset) {
|
|
Object.assign(element.dataset, dataset)
|
|
}
|
|
|
|
Object.assign(element, rest)
|
|
if (children) {
|
|
element.append(...(Array.isArray(children) ? children : [children]))
|
|
}
|
|
|
|
if (parent) {
|
|
parent.append(element)
|
|
}
|
|
|
|
if (cb) {
|
|
cb(element)
|
|
}
|
|
}
|
|
}
|
|
return element as ElementType<TTag>
|
|
}
|
|
|
|
// @ts-expect-error fixme ts strict error
|
|
function dragElement(dragEl): () => void {
|
|
var posDiffX = 0,
|
|
posDiffY = 0,
|
|
posStartX = 0,
|
|
posStartY = 0,
|
|
newPosX = 0,
|
|
newPosY = 0
|
|
if (dragEl.getElementsByClassName('drag-handle')[0]) {
|
|
// if present, the handle is where you move the DIV from:
|
|
dragEl.getElementsByClassName('drag-handle')[0].onmousedown = dragMouseDown
|
|
} else {
|
|
// otherwise, move the DIV from anywhere inside the DIV:
|
|
dragEl.onmousedown = dragMouseDown
|
|
}
|
|
|
|
// When the element resizes (e.g. view queue) ensure it is still in the windows bounds
|
|
new ResizeObserver(() => {
|
|
ensureInBounds()
|
|
}).observe(dragEl)
|
|
|
|
function ensureInBounds() {
|
|
try {
|
|
newPosX = Math.min(
|
|
document.body.clientWidth - dragEl.clientWidth,
|
|
Math.max(0, dragEl.offsetLeft)
|
|
)
|
|
newPosY = Math.min(
|
|
document.body.clientHeight - dragEl.clientHeight,
|
|
Math.max(0, dragEl.offsetTop)
|
|
)
|
|
|
|
positionElement()
|
|
} catch (exception) {
|
|
// robust
|
|
}
|
|
}
|
|
|
|
function positionElement() {
|
|
if (dragEl.style.display === 'none') return
|
|
|
|
const halfWidth = document.body.clientWidth / 2
|
|
const anchorRight = newPosX + dragEl.clientWidth / 2 > halfWidth
|
|
|
|
// set the element's new position:
|
|
if (anchorRight) {
|
|
dragEl.style.left = 'unset'
|
|
dragEl.style.right =
|
|
document.body.clientWidth - newPosX - dragEl.clientWidth + 'px'
|
|
} else {
|
|
dragEl.style.left = newPosX + 'px'
|
|
dragEl.style.right = 'unset'
|
|
}
|
|
|
|
dragEl.style.top = newPosY + 'px'
|
|
dragEl.style.bottom = 'unset'
|
|
|
|
// @ts-expect-error fixme ts strict error
|
|
if (savePos) {
|
|
localStorage.setItem(
|
|
'Comfy.MenuPosition',
|
|
JSON.stringify({
|
|
x: dragEl.offsetLeft,
|
|
y: dragEl.offsetTop
|
|
})
|
|
)
|
|
}
|
|
}
|
|
|
|
function restorePos() {
|
|
let posString = localStorage.getItem('Comfy.MenuPosition')
|
|
if (posString) {
|
|
const pos = JSON.parse(posString) as Position2D
|
|
newPosX = pos.x
|
|
newPosY = pos.y
|
|
positionElement()
|
|
ensureInBounds()
|
|
}
|
|
}
|
|
|
|
// @ts-expect-error fixme ts strict error
|
|
let savePos = undefined
|
|
restorePos()
|
|
savePos = true
|
|
|
|
// @ts-expect-error fixme ts strict error
|
|
function dragMouseDown(e) {
|
|
e = e || window.event
|
|
e.preventDefault()
|
|
// get the mouse cursor position at startup:
|
|
posStartX = e.clientX
|
|
posStartY = e.clientY
|
|
document.onmouseup = closeDragElement
|
|
// call a function whenever the cursor moves:
|
|
document.onmousemove = elementDrag
|
|
}
|
|
|
|
// @ts-expect-error fixme ts strict error
|
|
function elementDrag(e) {
|
|
e = e || window.event
|
|
e.preventDefault()
|
|
|
|
dragEl.classList.add('comfy-menu-manual-pos')
|
|
|
|
// calculate the new cursor position:
|
|
posDiffX = e.clientX - posStartX
|
|
posDiffY = e.clientY - posStartY
|
|
posStartX = e.clientX
|
|
posStartY = e.clientY
|
|
|
|
newPosX = Math.min(
|
|
document.body.clientWidth - dragEl.clientWidth,
|
|
Math.max(0, dragEl.offsetLeft + posDiffX)
|
|
)
|
|
newPosY = Math.min(
|
|
document.body.clientHeight - dragEl.clientHeight,
|
|
Math.max(0, dragEl.offsetTop + posDiffY)
|
|
)
|
|
|
|
positionElement()
|
|
}
|
|
|
|
window.addEventListener('resize', () => {
|
|
ensureInBounds()
|
|
})
|
|
|
|
function closeDragElement() {
|
|
// stop moving when mouse button is released:
|
|
document.onmouseup = null
|
|
document.onmousemove = null
|
|
}
|
|
|
|
return restorePos
|
|
}
|
|
|
|
class ComfyList {
|
|
#type
|
|
#text
|
|
#reverse
|
|
element: HTMLDivElement
|
|
button?: HTMLButtonElement
|
|
|
|
// @ts-expect-error fixme ts strict error
|
|
constructor(text, type?, reverse?) {
|
|
this.#text = text
|
|
this.#type = type || text.toLowerCase()
|
|
this.#reverse = reverse || false
|
|
this.element = $el('div.comfy-list') as HTMLDivElement
|
|
this.element.style.display = 'none'
|
|
}
|
|
|
|
get visible() {
|
|
return this.element.style.display !== 'none'
|
|
}
|
|
|
|
async load() {
|
|
const items = await api.getItems(this.#type)
|
|
this.element.replaceChildren(
|
|
...Object.keys(items).flatMap((section) => [
|
|
$el('h4', {
|
|
textContent: section
|
|
}),
|
|
$el('div.comfy-list-items', [
|
|
// @ts-expect-error fixme ts strict error
|
|
...(this.#reverse ? items[section].reverse() : items[section]).map(
|
|
(item: LegacyQueueItem) => {
|
|
// Allow items to specify a custom remove action (e.g. for interrupt current prompt)
|
|
const removeAction = item.remove ?? {
|
|
name: 'Delete',
|
|
cb: () => api.deleteItem(this.#type, item.prompt[1])
|
|
}
|
|
return $el('div', { textContent: item.prompt[0] + ': ' }, [
|
|
$el('button', {
|
|
textContent: 'Load',
|
|
onclick: async () => {
|
|
await app.loadGraphData(
|
|
item.prompt[3].extra_pnginfo.workflow as Parameters<
|
|
typeof app.loadGraphData
|
|
>[0],
|
|
true,
|
|
false
|
|
)
|
|
if ('outputs' in item && item.outputs) {
|
|
app.nodeOutputs = {}
|
|
for (const [key, value] of Object.entries(item.outputs)) {
|
|
const realKey = item['meta']?.[key]?.display_node ?? key
|
|
// @ts-expect-error fixme ts strict error
|
|
app.nodeOutputs[realKey] = value
|
|
}
|
|
}
|
|
}
|
|
}),
|
|
$el('button', {
|
|
textContent: removeAction.name,
|
|
onclick: async () => {
|
|
await removeAction.cb()
|
|
await this.update()
|
|
}
|
|
})
|
|
])
|
|
}
|
|
)
|
|
])
|
|
]),
|
|
$el('div.comfy-list-actions', [
|
|
$el('button', {
|
|
textContent: 'Clear ' + this.#text,
|
|
onclick: async () => {
|
|
await api.clearItems(this.#type)
|
|
await this.load()
|
|
}
|
|
}),
|
|
$el('button', { textContent: 'Refresh', onclick: () => this.load() })
|
|
])
|
|
)
|
|
}
|
|
|
|
async update() {
|
|
if (this.visible) {
|
|
await this.load()
|
|
}
|
|
}
|
|
|
|
async show() {
|
|
this.element.style.display = 'block'
|
|
// @ts-expect-error fixme ts strict error
|
|
this.button.textContent = 'Close'
|
|
|
|
await this.load()
|
|
}
|
|
|
|
hide() {
|
|
this.element.style.display = 'none'
|
|
// @ts-expect-error fixme ts strict error
|
|
this.button.textContent = 'View ' + this.#text
|
|
}
|
|
|
|
toggle() {
|
|
if (this.visible) {
|
|
this.hide()
|
|
return false
|
|
} else {
|
|
this.show()
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
export class ComfyUI {
|
|
app: ComfyApp
|
|
dialog: _ComfyDialog
|
|
settings: ComfySettingsDialog
|
|
batchCount: number
|
|
lastQueueSize: number
|
|
queue: ComfyList
|
|
history: ComfyList
|
|
// @ts-expect-error fixme ts strict error
|
|
autoQueueMode: string
|
|
// @ts-expect-error fixme ts strict error
|
|
graphHasChanged: boolean
|
|
// @ts-expect-error fixme ts strict error
|
|
autoQueueEnabled: boolean
|
|
// @ts-expect-error fixme ts strict error
|
|
menuContainer: HTMLDivElement
|
|
// @ts-expect-error fixme ts strict error
|
|
queueSize: Element
|
|
// @ts-expect-error fixme ts strict error
|
|
restoreMenuPosition: () => void
|
|
// @ts-expect-error fixme ts strict error
|
|
loadFile: () => void
|
|
|
|
// @ts-expect-error fixme ts strict error
|
|
constructor(app) {
|
|
this.app = app
|
|
this.dialog = new ComfyDialog()
|
|
this.settings = new ComfySettingsDialog(app)
|
|
|
|
this.batchCount = 1
|
|
this.lastQueueSize = 0
|
|
this.queue = new ComfyList('Queue')
|
|
this.history = new ComfyList('History', 'history', true)
|
|
|
|
api.addEventListener('status', () => {
|
|
this.queue.update()
|
|
this.history.update()
|
|
})
|
|
|
|
this.setup(document.body)
|
|
}
|
|
|
|
setup(containerElement: HTMLElement) {
|
|
const fileInput = $el('input', {
|
|
id: 'comfy-file-input',
|
|
type: 'file',
|
|
accept: WORKFLOW_ACCEPT_STRING,
|
|
style: { display: 'none' },
|
|
parent: document.body,
|
|
onchange: async () => {
|
|
const file = fileInput.files?.[0]
|
|
if (file) {
|
|
await app.handleFile(file, 'file_button')
|
|
fileInput.value = ''
|
|
}
|
|
}
|
|
})
|
|
|
|
this.loadFile = () => fileInput.click()
|
|
|
|
const autoQueueModeEl = toggleSwitch(
|
|
'autoQueueMode',
|
|
[
|
|
{
|
|
text: 'instant',
|
|
tooltip: 'A new prompt will be queued as soon as the queue reaches 0'
|
|
},
|
|
{
|
|
text: 'change',
|
|
tooltip:
|
|
'A new prompt will be queued when the queue is at 0 and the graph is/has changed'
|
|
}
|
|
],
|
|
{
|
|
// @ts-expect-error fixme ts strict error
|
|
onChange: (value) => {
|
|
this.autoQueueMode = value.item.value
|
|
}
|
|
}
|
|
)
|
|
autoQueueModeEl.style.display = 'none'
|
|
|
|
api.addEventListener('graphChanged', () => {
|
|
if (this.autoQueueMode === 'change' && this.autoQueueEnabled === true) {
|
|
if (this.lastQueueSize === 0) {
|
|
this.graphHasChanged = false
|
|
app.queuePrompt(0, this.batchCount)
|
|
} else {
|
|
this.graphHasChanged = true
|
|
}
|
|
}
|
|
})
|
|
|
|
this.menuContainer = $el(
|
|
'div.comfy-menu.no-drag',
|
|
{ parent: containerElement },
|
|
[
|
|
$el(
|
|
'div.drag-handle.comfy-menu-header',
|
|
{
|
|
style: {
|
|
overflow: 'hidden',
|
|
position: 'relative',
|
|
width: '100%',
|
|
cursor: 'default'
|
|
}
|
|
},
|
|
[
|
|
$el('span.drag-handle'),
|
|
$el('span.comfy-menu-queue-size', {
|
|
$: (q) => (this.queueSize = q)
|
|
}),
|
|
$el('div.comfy-menu-actions', [
|
|
$el('button.comfy-settings-btn', {
|
|
textContent: '⚙️',
|
|
onclick: () => {
|
|
useDialogService().showSettingsDialog()
|
|
}
|
|
}),
|
|
$el('button.comfy-close-menu-btn', {
|
|
textContent: '\u00d7',
|
|
onclick: () => {
|
|
useWorkspaceStore().focusMode = true
|
|
}
|
|
})
|
|
])
|
|
]
|
|
),
|
|
$el('button.comfy-queue-btn', {
|
|
id: 'queue-button',
|
|
textContent: 'Queue Prompt',
|
|
onclick: () => {
|
|
if (isCloud) {
|
|
useTelemetry()?.trackRunButton({ trigger_source: 'legacy_ui' })
|
|
useTelemetry()?.trackWorkflowExecution()
|
|
}
|
|
app.queuePrompt(0, this.batchCount)
|
|
}
|
|
}),
|
|
$el('div', {}, [
|
|
$el('label', { innerHTML: 'Extra options' }, [
|
|
$el('input', {
|
|
type: 'checkbox',
|
|
// @ts-expect-error fixme ts strict error
|
|
onchange: (i) => {
|
|
// @ts-expect-error fixme ts strict error
|
|
document.getElementById('extraOptions').style.display = i
|
|
.srcElement.checked
|
|
? 'block'
|
|
: 'none'
|
|
this.batchCount = i.srcElement.checked
|
|
? Number.parseInt(
|
|
(
|
|
document.getElementById(
|
|
'batchCountInputRange'
|
|
) as HTMLInputElement
|
|
).value
|
|
)
|
|
: 1
|
|
;(
|
|
document.getElementById(
|
|
'autoQueueCheckbox'
|
|
) as HTMLInputElement
|
|
).checked = false
|
|
this.autoQueueEnabled = false
|
|
}
|
|
})
|
|
])
|
|
]),
|
|
$el(
|
|
'div',
|
|
{ id: 'extraOptions', style: { width: '100%', display: 'none' } },
|
|
[
|
|
$el('div', [
|
|
$el('label', { innerHTML: 'Batch count' }),
|
|
$el('input', {
|
|
id: 'batchCountInputNumber',
|
|
type: 'number',
|
|
value: this.batchCount,
|
|
min: '1',
|
|
style: { width: '35%', marginLeft: '0.4em' },
|
|
// @ts-expect-error fixme ts strict error
|
|
oninput: (i) => {
|
|
this.batchCount = i.target.value
|
|
/* Even though an <input> element with a type of range logically represents a number (since
|
|
it's used for numeric input), the value it holds is still treated as a string in HTML and
|
|
JavaScript. This behavior is consistent across all <input> elements regardless of their type
|
|
(like text, number, or range), where the .value property is always a string. */
|
|
;(
|
|
document.getElementById(
|
|
'batchCountInputRange'
|
|
) as HTMLInputElement
|
|
).value = this.batchCount.toString()
|
|
}
|
|
}),
|
|
$el('input', {
|
|
id: 'batchCountInputRange',
|
|
type: 'range',
|
|
min: '1',
|
|
max: '100',
|
|
value: this.batchCount,
|
|
// @ts-expect-error fixme ts strict error
|
|
oninput: (i) => {
|
|
this.batchCount = i.srcElement.value
|
|
// Note
|
|
;(
|
|
document.getElementById(
|
|
'batchCountInputNumber'
|
|
) as HTMLInputElement
|
|
).value = i.srcElement.value
|
|
}
|
|
})
|
|
]),
|
|
$el('div', [
|
|
$el('label', {
|
|
for: 'autoQueueCheckbox',
|
|
innerHTML: 'Auto Queue'
|
|
}),
|
|
$el('input', {
|
|
id: 'autoQueueCheckbox',
|
|
type: 'checkbox',
|
|
checked: false,
|
|
title: 'Automatically queue prompt when the queue size hits 0',
|
|
// @ts-expect-error fixme ts strict error
|
|
onchange: (e) => {
|
|
this.autoQueueEnabled = e.target.checked
|
|
autoQueueModeEl.style.display = this.autoQueueEnabled
|
|
? ''
|
|
: 'none'
|
|
}
|
|
}),
|
|
autoQueueModeEl
|
|
])
|
|
]
|
|
),
|
|
$el('div.comfy-menu-btns', [
|
|
$el('button', {
|
|
id: 'queue-front-button',
|
|
textContent: 'Queue Front',
|
|
onclick: () => {
|
|
if (isCloud) {
|
|
useTelemetry()?.trackRunButton({ trigger_source: 'legacy_ui' })
|
|
useTelemetry()?.trackWorkflowExecution()
|
|
}
|
|
app.queuePrompt(-1, this.batchCount)
|
|
}
|
|
}),
|
|
$el('button', {
|
|
$: (b) => (this.queue.button = b as HTMLButtonElement),
|
|
id: 'comfy-view-queue-button',
|
|
textContent: 'View Queue',
|
|
onclick: () => {
|
|
this.history.hide()
|
|
this.queue.toggle()
|
|
}
|
|
}),
|
|
$el('button', {
|
|
$: (b) => (this.history.button = b as HTMLButtonElement),
|
|
id: 'comfy-view-history-button',
|
|
textContent: 'View History',
|
|
onclick: () => {
|
|
this.queue.hide()
|
|
this.history.toggle()
|
|
}
|
|
})
|
|
]),
|
|
this.queue.element,
|
|
this.history.element,
|
|
$el('button', {
|
|
id: 'comfy-save-button',
|
|
textContent: 'Save',
|
|
onclick: () => {
|
|
useCommandStore().execute('Comfy.ExportWorkflow')
|
|
}
|
|
}),
|
|
$el('button', {
|
|
id: 'comfy-dev-save-api-button',
|
|
textContent: 'Save (API Format)',
|
|
style: { width: '100%', display: 'none' },
|
|
onclick: () => {
|
|
useCommandStore().execute('Comfy.ExportWorkflowAPI')
|
|
}
|
|
}),
|
|
$el('button', {
|
|
id: 'comfy-load-button',
|
|
textContent: 'Load',
|
|
onclick: () => fileInput.click()
|
|
}),
|
|
$el('button', {
|
|
id: 'comfy-refresh-button',
|
|
textContent: 'Refresh',
|
|
onclick: () => app.refreshComboInNodes()
|
|
}),
|
|
$el('button', {
|
|
id: 'comfy-clipspace-button',
|
|
textContent: 'Clipspace',
|
|
onclick: () => app.openClipspace()
|
|
}),
|
|
$el('button', {
|
|
id: 'comfy-clear-button',
|
|
textContent: 'Clear',
|
|
onclick: () => {
|
|
if (
|
|
!useSettingStore().get('Comfy.ConfirmClear') ||
|
|
confirm('Clear workflow?')
|
|
) {
|
|
app.clean()
|
|
useLitegraphService().resetView()
|
|
api.dispatchCustomEvent('graphCleared')
|
|
}
|
|
}
|
|
}),
|
|
$el('button', {
|
|
id: 'comfy-load-default-button',
|
|
textContent: 'Load Default',
|
|
onclick: async () => {
|
|
if (
|
|
!useSettingStore().get('Comfy.ConfirmClear') ||
|
|
confirm('Load default workflow?')
|
|
) {
|
|
useLitegraphService().resetView()
|
|
await app.loadGraphData()
|
|
}
|
|
}
|
|
}),
|
|
$el('button', {
|
|
id: 'comfy-reset-view-button',
|
|
textContent: 'Reset View',
|
|
onclick: async () => {
|
|
useLitegraphService().resetView()
|
|
}
|
|
})
|
|
]
|
|
) as HTMLDivElement
|
|
// Hide by default on construction so it does not interfere with other views.
|
|
this.menuContainer.style.display = 'none'
|
|
|
|
this.restoreMenuPosition = dragElement(this.menuContainer)
|
|
|
|
// @ts-expect-error
|
|
this.setStatus({ exec_info: { queue_remaining: 'X' } })
|
|
}
|
|
|
|
setStatus(status: StatusWsMessageStatus | null) {
|
|
this.queueSize.textContent =
|
|
'Queue size: ' + (status ? status.exec_info.queue_remaining : 'ERR')
|
|
if (status) {
|
|
if (
|
|
this.lastQueueSize != 0 &&
|
|
status.exec_info.queue_remaining == 0 &&
|
|
this.autoQueueEnabled &&
|
|
(this.autoQueueMode === 'instant' || this.graphHasChanged) &&
|
|
!app.lastExecutionError
|
|
) {
|
|
app.queuePrompt(0, this.batchCount)
|
|
status.exec_info.queue_remaining += this.batchCount
|
|
this.graphHasChanged = false
|
|
}
|
|
this.lastQueueSize = status.exec_info.queue_remaining
|
|
}
|
|
}
|
|
}
|