mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-03 22:59:14 +00:00
merge main into rh-test
This commit is contained in:
@@ -1,7 +1,19 @@
|
||||
import axios from 'axios'
|
||||
import { debounce } from 'es-toolkit/compat'
|
||||
import { get } from 'es-toolkit/compat'
|
||||
|
||||
import defaultClientFeatureFlags from '@/config/clientFeatureFlags.json'
|
||||
import defaultClientFeatureFlags from '@/config/clientFeatureFlags.json' with { type: 'json' }
|
||||
import type {
|
||||
ModelFile,
|
||||
ModelFolderInfo
|
||||
} from '@/platform/assets/schemas/assetSchema'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
import { type WorkflowTemplates } from '@/platform/workflow/templates/types/template'
|
||||
import type {
|
||||
ComfyApiWorkflow,
|
||||
ComfyWorkflowJSON,
|
||||
NodeId
|
||||
} from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import type {
|
||||
DisplayComponentWsMessage,
|
||||
EmbeddingsResponse,
|
||||
@@ -33,16 +45,9 @@ import type {
|
||||
User,
|
||||
UserDataFullInfo
|
||||
} from '@/schemas/apiSchema'
|
||||
import type {
|
||||
ComfyApiWorkflow,
|
||||
ComfyWorkflowJSON,
|
||||
NodeId
|
||||
} from '@/schemas/comfyWorkflowSchema'
|
||||
import type { ComfyNodeDef } from '@/schemas/nodeDefSchema'
|
||||
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
import type { NodeExecutionId } from '@/types/nodeIdentification'
|
||||
import { WorkflowTemplates } from '@/types/workflowTemplateTypes'
|
||||
|
||||
interface QueuePromptRequestBody {
|
||||
client_id: string
|
||||
@@ -788,11 +793,28 @@ export class ComfyApi extends EventTarget {
|
||||
|
||||
/**
|
||||
* Gets the index of core workflow templates.
|
||||
* @param locale Optional locale code (e.g., 'en', 'fr', 'zh') to load localized templates
|
||||
*/
|
||||
async getCoreWorkflowTemplates(): Promise<WorkflowTemplates[]> {
|
||||
const res = await axios.get(this.fileURL('/templates/index.json'))
|
||||
const contentType = res.headers['content-type']
|
||||
return contentType?.includes('application/json') ? res.data : []
|
||||
async getCoreWorkflowTemplates(
|
||||
locale?: string
|
||||
): Promise<WorkflowTemplates[]> {
|
||||
const fileName =
|
||||
locale && locale !== 'en' ? `index.${locale}.json` : 'index.json'
|
||||
try {
|
||||
const res = await axios.get(this.fileURL(`/templates/${fileName}`))
|
||||
const contentType = res.headers['content-type']
|
||||
return contentType?.includes('application/json') ? res.data : []
|
||||
} catch (error) {
|
||||
// Fallback to default English version if localized version doesn't exist
|
||||
if (locale && locale !== 'en') {
|
||||
console.warn(
|
||||
`Localized templates for '${locale}' not found, falling back to English`
|
||||
)
|
||||
return this.getCoreWorkflowTemplates()
|
||||
}
|
||||
console.error('Error loading core workflow templates:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -864,14 +886,14 @@ export class ComfyApi extends EventTarget {
|
||||
* Gets a list of model folder keys (eg ['checkpoints', 'loras', ...])
|
||||
* @returns The list of model folder keys
|
||||
*/
|
||||
async getModelFolders(): Promise<{ name: string; folders: string[] }[]> {
|
||||
async getModelFolders(): Promise<ModelFolderInfo[]> {
|
||||
const res = await this.fetchApi(`/experiment/models`)
|
||||
if (res.status === 404) {
|
||||
return []
|
||||
}
|
||||
const folderBlacklist = ['configs', 'custom_nodes']
|
||||
return (await res.json()).filter(
|
||||
(folder: string) => !folderBlacklist.includes(folder)
|
||||
(folder: ModelFolderInfo) => !folderBlacklist.includes(folder.name)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -880,9 +902,7 @@ export class ComfyApi extends EventTarget {
|
||||
* @param {string} folder The folder to list models from, such as 'checkpoints'
|
||||
* @returns The list of model filenames within the specified folder
|
||||
*/
|
||||
async getModels(
|
||||
folder: string
|
||||
): Promise<{ name: string; pathIndex: number }[]> {
|
||||
async getModels(folder: string): Promise<ModelFile[]> {
|
||||
const res = await this.fetchApi(`/experiment/models/${folder}`)
|
||||
if (res.status === 404) {
|
||||
return []
|
||||
@@ -1263,7 +1283,63 @@ export class ComfyApi extends EventTarget {
|
||||
}
|
||||
|
||||
async getFolderPaths(): Promise<Record<string, string[]>> {
|
||||
return (await axios.get(this.internalURL('/folder_paths'))).data
|
||||
const response = await axios
|
||||
.get(this.internalURL('/folder_paths'))
|
||||
.catch(() => null)
|
||||
if (!response) {
|
||||
return {} // Fallback: no filesystem paths known when API unavailable
|
||||
}
|
||||
return response.data
|
||||
}
|
||||
|
||||
/* Frees memory by unloading models and optionally freeing execution cache
|
||||
* @param {Object} options - The options object
|
||||
* @param {boolean} options.freeExecutionCache - If true, also frees execution cache
|
||||
*/
|
||||
async freeMemory(options: { freeExecutionCache: boolean }) {
|
||||
try {
|
||||
let mode = ''
|
||||
if (options.freeExecutionCache) {
|
||||
mode = '{"unload_models": true, "free_memory": true}'
|
||||
} else {
|
||||
mode = '{"unload_models": true}'
|
||||
}
|
||||
|
||||
const res = await this.fetchApi(`/free`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: mode
|
||||
})
|
||||
|
||||
if (res.status === 200) {
|
||||
if (options.freeExecutionCache) {
|
||||
useToastStore().add({
|
||||
severity: 'success',
|
||||
summary: 'Models and Execution Cache have been cleared.',
|
||||
life: 3000
|
||||
})
|
||||
} else {
|
||||
useToastStore().add({
|
||||
severity: 'success',
|
||||
summary: 'Models have been unloaded.',
|
||||
life: 3000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
useToastStore().add({
|
||||
severity: 'error',
|
||||
summary:
|
||||
'Unloading of models failed. Installed ComfyUI may be an outdated version.',
|
||||
life: 5000
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
useToastStore().add({
|
||||
severity: 'error',
|
||||
summary: 'An error occurred while trying to unload models.',
|
||||
life: 5000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1277,21 +1353,21 @@ export class ComfyApi extends EventTarget {
|
||||
|
||||
/**
|
||||
* Checks if the server supports a specific feature.
|
||||
* @param featureName The name of the feature to check
|
||||
* @param featureName The name of the feature to check (supports dot notation for nested values)
|
||||
* @returns true if the feature is supported, false otherwise
|
||||
*/
|
||||
serverSupportsFeature(featureName: string): boolean {
|
||||
return this.serverFeatureFlags[featureName] === true
|
||||
return get(this.serverFeatureFlags, featureName) === true
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a server feature flag value.
|
||||
* @param featureName The name of the feature to get
|
||||
* @param featureName The name of the feature to get (supports dot notation for nested values)
|
||||
* @param defaultValue The default value if the feature is not found
|
||||
* @returns The feature value or default
|
||||
*/
|
||||
getServerFeature<T = unknown>(featureName: string, defaultValue?: T): T {
|
||||
return (this.serverFeatureFlags[featureName] ?? defaultValue) as T
|
||||
return get(this.serverFeatureFlags, featureName, defaultValue) as T
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { ToastMessageOptions } from 'primevue/toast'
|
||||
import { reactive } from 'vue'
|
||||
|
||||
import { useCanvasPositionConversion } from '@/composables/element/useCanvasPositionConversion'
|
||||
import { useWorkflowValidation } from '@/composables/useWorkflowValidation'
|
||||
import { st, t } from '@/i18n'
|
||||
import {
|
||||
LGraph,
|
||||
@@ -14,23 +13,29 @@ import {
|
||||
} from '@/lib/litegraph/src/litegraph'
|
||||
import type { Vector2 } from '@/lib/litegraph/src/litegraph'
|
||||
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
|
||||
import { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
|
||||
import { useWorkflowValidation } from '@/platform/workflow/validation/composables/useWorkflowValidation'
|
||||
import {
|
||||
type ComfyApiWorkflow,
|
||||
type ComfyWorkflowJSON,
|
||||
type ModelFile,
|
||||
type NodeId,
|
||||
isSubgraphDefinition
|
||||
} from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import type {
|
||||
ExecutionErrorWsMessage,
|
||||
NodeError,
|
||||
ResultItem
|
||||
} from '@/schemas/apiSchema'
|
||||
import {
|
||||
ComfyApiWorkflow,
|
||||
type ComfyWorkflowJSON,
|
||||
type ModelFile,
|
||||
type NodeId,
|
||||
isSubgraphDefinition
|
||||
} from '@/schemas/comfyWorkflowSchema'
|
||||
import {
|
||||
type ComfyNodeDef as ComfyNodeDefV1,
|
||||
isComboInputSpecV1,
|
||||
isComboInputSpecV2
|
||||
} from '@/schemas/nodeDefSchema'
|
||||
import { type BaseDOMWidget, DOMWidgetImpl } from '@/scripts/domWidget'
|
||||
import { getFromWebmFile } from '@/scripts/metadata/ebml'
|
||||
import { getGltfBinaryMetadata } from '@/scripts/metadata/gltf'
|
||||
import { getFromIsobmffFile } from '@/scripts/metadata/isobmff'
|
||||
@@ -41,7 +46,6 @@ import { useDialogService } from '@/services/dialogService'
|
||||
import { useExtensionService } from '@/services/extensionService'
|
||||
import { useLitegraphService } from '@/services/litegraphService'
|
||||
import { useSubgraphService } from '@/services/subgraphService'
|
||||
import { useWorkflowService } from '@/services/workflowService'
|
||||
import { useApiKeyAuthStore } from '@/stores/apiKeyAuthStore'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { useDomWidgetStore } from '@/stores/domWidgetStore'
|
||||
@@ -52,16 +56,14 @@ import { useNodeOutputStore } from '@/stores/imagePreviewStore'
|
||||
import { KeyComboImpl, useKeybindingStore } from '@/stores/keybindingStore'
|
||||
import { useModelStore } from '@/stores/modelStore'
|
||||
import { SYSTEM_NODE_DEFS, useNodeDefStore } from '@/stores/nodeDefStore'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
import { useSubgraphStore } from '@/stores/subgraphStore'
|
||||
import { useWidgetStore } from '@/stores/widgetStore'
|
||||
import { ComfyWorkflow } from '@/stores/workflowStore'
|
||||
import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
import type { ComfyExtension, MissingNodeType } from '@/types/comfy'
|
||||
import { ExtensionManager } from '@/types/extensionTypes'
|
||||
import { type ExtensionManager } from '@/types/extensionTypes'
|
||||
import type { NodeExecutionId } from '@/types/nodeIdentification'
|
||||
import { ColorAdjustOptions, adjustColor } from '@/utils/colorUtil'
|
||||
import { type ColorAdjustOptions, adjustColor } from '@/utils/colorUtil'
|
||||
import { graphToPrompt } from '@/utils/executionUtil'
|
||||
import { forEachNode } from '@/utils/graphTraversalUtil'
|
||||
import {
|
||||
@@ -155,11 +157,22 @@ export class ComfyApp {
|
||||
// @ts-expect-error fixme ts strict error
|
||||
_nodeOutputs: Record<string, any>
|
||||
nodePreviewImages: Record<string, string[]>
|
||||
// @ts-expect-error fixme ts strict error
|
||||
#graph: LGraph
|
||||
|
||||
private rootGraphInternal: LGraph | undefined
|
||||
|
||||
// TODO: Migrate internal usage to the
|
||||
/** @deprecated Use {@link rootGraph} instead */
|
||||
get graph() {
|
||||
return this.#graph
|
||||
return this.rootGraphInternal!
|
||||
}
|
||||
|
||||
get rootGraph(): LGraph | undefined {
|
||||
if (!this.rootGraphInternal) {
|
||||
console.error('ComfyApp graph accessed before initialization')
|
||||
}
|
||||
return this.rootGraphInternal
|
||||
}
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
canvas: LGraphCanvas
|
||||
dragOverNode: LGraphNode | null = null
|
||||
@@ -602,7 +615,10 @@ export class ComfyApp {
|
||||
const keybindingStore = useKeybindingStore()
|
||||
const keybinding = keybindingStore.getKeybinding(keyCombo)
|
||||
|
||||
if (keybinding && keybinding.targetElementId === 'graph-canvas') {
|
||||
if (
|
||||
keybinding &&
|
||||
keybinding.targetElementId === 'graph-canvas-container'
|
||||
) {
|
||||
useCommandStore().execute(keybinding.commandId)
|
||||
|
||||
this.graph.change()
|
||||
@@ -657,7 +673,7 @@ export class ComfyApp {
|
||||
if (opacity) adjustments.opacity = opacity
|
||||
|
||||
if (useColorPaletteStore().completedActivePalette.light_theme) {
|
||||
adjustments.lightness = 0.5
|
||||
if (old_bgcolor) adjustments.lightness = 0.5
|
||||
|
||||
// Lighten title bar of colored nodes on light theme
|
||||
if (old_color) {
|
||||
@@ -768,8 +784,7 @@ export class ComfyApp {
|
||||
}
|
||||
}
|
||||
|
||||
#addAfterConfigureHandler() {
|
||||
const { graph } = this
|
||||
private addAfterConfigureHandler(graph: LGraph) {
|
||||
const { onConfigure } = graph
|
||||
graph.onConfigure = function (...args) {
|
||||
fixLinkInputSlots(this)
|
||||
@@ -805,16 +820,17 @@ export class ComfyApp {
|
||||
this.resizeCanvas()
|
||||
|
||||
await useWorkspaceStore().workflow.syncWorkflows()
|
||||
await useSubgraphStore().fetchSubgraphs()
|
||||
await useExtensionService().loadExtensions()
|
||||
|
||||
this.#addProcessKeyHandler()
|
||||
this.#addConfigureHandler()
|
||||
this.#addApiUpdateHandlers()
|
||||
|
||||
this.#graph = new LGraph()
|
||||
const graph = new LGraph()
|
||||
|
||||
// Register the subgraph - adds type wrapper for Litegraph's `createNode` factory
|
||||
this.graph.events.addEventListener('subgraph-created', (e) => {
|
||||
graph.events.addEventListener('subgraph-created', (e) => {
|
||||
try {
|
||||
const { subgraph, data } = e.detail
|
||||
useSubgraphService().registerNewSubgraph(subgraph, data)
|
||||
@@ -828,9 +844,10 @@ export class ComfyApp {
|
||||
}
|
||||
})
|
||||
|
||||
this.#addAfterConfigureHandler()
|
||||
this.addAfterConfigureHandler(graph)
|
||||
|
||||
this.canvas = new LGraphCanvas(canvasEl, this.graph)
|
||||
this.rootGraphInternal = graph
|
||||
this.canvas = new LGraphCanvas(canvasEl, graph)
|
||||
// Make canvas states reactive so we can observe changes on them.
|
||||
this.canvas.state = reactive(this.canvas.state)
|
||||
|
||||
@@ -843,22 +860,29 @@ export class ComfyApp {
|
||||
this.canvas.canvas.addEventListener<'litegraph:set-graph'>(
|
||||
'litegraph:set-graph',
|
||||
(e) => {
|
||||
// Assertion: Not yet defined in litegraph.
|
||||
const { newGraph } = e.detail
|
||||
|
||||
const nodeSet = new Set(newGraph.nodes)
|
||||
const widgetStore = useDomWidgetStore()
|
||||
|
||||
// Assertions: UnwrapRef
|
||||
for (const { widget } of widgetStore.activeWidgetStates) {
|
||||
if (!nodeSet.has(widget.node)) {
|
||||
widgetStore.deactivateWidget(widget.id)
|
||||
}
|
||||
}
|
||||
const activeWidgets: Record<
|
||||
string,
|
||||
BaseDOMWidget<object | string>
|
||||
> = Object.fromEntries(
|
||||
newGraph.nodes
|
||||
.flatMap((node) => node.widgets ?? [])
|
||||
.filter((w) => w instanceof DOMWidgetImpl)
|
||||
.map((w) => [w.id, w])
|
||||
)
|
||||
|
||||
for (const { widget } of widgetStore.inactiveWidgetStates) {
|
||||
if (nodeSet.has(widget.node)) {
|
||||
widgetStore.activateWidget(widget.id)
|
||||
for (const [
|
||||
widgetId,
|
||||
widgetState
|
||||
] of widgetStore.widgetStates.entries()) {
|
||||
if (widgetId in activeWidgets) {
|
||||
widgetState.active = true
|
||||
widgetState.widget = activeWidgets[widgetId]
|
||||
} else {
|
||||
widgetState.active = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -913,7 +937,7 @@ export class ComfyApp {
|
||||
LiteGraph.registered_node_types
|
||||
)) {
|
||||
// Skip if we already have a backend definition or system definition
|
||||
if (name in defs || name in SYSTEM_NODE_DEFS) {
|
||||
if (name in defs || name in SYSTEM_NODE_DEFS || node.skip_list) {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1080,6 +1104,8 @@ export class ComfyApp {
|
||||
checkForRerouteMigration = false
|
||||
} = {}
|
||||
) {
|
||||
useWorkflowService().beforeLoadNewGraph()
|
||||
|
||||
if (clean !== false) {
|
||||
this.clean()
|
||||
}
|
||||
@@ -1115,7 +1141,6 @@ export class ComfyApp {
|
||||
severity: 'warn'
|
||||
})
|
||||
}
|
||||
useWorkflowService().beforeLoadNewGraph()
|
||||
useSubgraphService().loadSubgraphs(graphData)
|
||||
|
||||
const missingNodeTypes: MissingNodeType[] = []
|
||||
@@ -1132,6 +1157,13 @@ export class ComfyApp {
|
||||
nodes: ComfyWorkflowJSON['nodes'],
|
||||
path: string = ''
|
||||
) => {
|
||||
if (!Array.isArray(nodes)) {
|
||||
console.warn(
|
||||
'Workflow nodes data is missing or invalid, skipping node processing',
|
||||
{ nodes, path }
|
||||
)
|
||||
return
|
||||
}
|
||||
for (let n of nodes) {
|
||||
// Patch T2IAdapterLoader to ControlNetLoader since they are the same node now
|
||||
if (n.type == 'T2IAdapterLoader') n.type = 'ControlNetLoader'
|
||||
@@ -1790,14 +1822,19 @@ export class ComfyApp {
|
||||
* Clean current state
|
||||
*/
|
||||
clean() {
|
||||
this.nodeOutputs = {}
|
||||
const { revokeAllPreviews } = useNodeOutputStore()
|
||||
revokeAllPreviews()
|
||||
const nodeOutputStore = useNodeOutputStore()
|
||||
nodeOutputStore.resetAllOutputsAndPreviews()
|
||||
const executionStore = useExecutionStore()
|
||||
executionStore.lastNodeErrors = null
|
||||
executionStore.lastExecutionError = null
|
||||
|
||||
useDomWidgetStore().clear()
|
||||
|
||||
// Subgraph does not properly implement `clear` and the parent class's
|
||||
// (`LGraph`) `clear` breaks the subgraph structure.
|
||||
if (this.graph && !this.canvas.subgraph) {
|
||||
this.graph.clear()
|
||||
}
|
||||
}
|
||||
|
||||
clientPosToCanvasPos(pos: Vector2): Vector2 {
|
||||
|
||||
@@ -3,11 +3,15 @@ import * as jsondiffpatch from 'jsondiffpatch'
|
||||
import log from 'loglevel'
|
||||
|
||||
import { LGraphCanvas, LiteGraph } from '@/lib/litegraph/src/litegraph'
|
||||
import {
|
||||
ComfyWorkflow,
|
||||
useWorkflowStore
|
||||
} from '@/platform/workflow/management/stores/workflowStore'
|
||||
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import type { ExecutedWsMessage } from '@/schemas/apiSchema'
|
||||
import type { ComfyWorkflowJSON } from '@/schemas/comfyWorkflowSchema'
|
||||
import { useExecutionStore } from '@/stores/executionStore'
|
||||
import { useNodeOutputStore } from '@/stores/imagePreviewStore'
|
||||
import { useSubgraphNavigationStore } from '@/stores/subgraphNavigationStore'
|
||||
import { ComfyWorkflow, useWorkflowStore } from '@/stores/workflowStore'
|
||||
|
||||
import { api } from './api'
|
||||
import type { ComfyApp } from './app'
|
||||
@@ -83,7 +87,7 @@ export class ChangeTracker {
|
||||
app.canvas.ds.offset = this.ds.offset
|
||||
}
|
||||
if (this.nodeOutputs) {
|
||||
app.nodeOutputs = this.nodeOutputs
|
||||
useNodeOutputStore().restoreOutputs(this.nodeOutputs)
|
||||
}
|
||||
if (this.subgraphState) {
|
||||
const { navigation } = this.subgraphState
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ComfyWorkflowJSON } from '@/schemas/comfyWorkflowSchema'
|
||||
import type { ComfyWorkflowJSON } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
|
||||
export const defaultGraph: ComfyWorkflowJSON = {
|
||||
last_node_id: 9,
|
||||
|
||||
@@ -55,7 +55,7 @@ export interface DOMWidget<T extends HTMLElement, V extends object | string>
|
||||
* - widget: Reference to the widget instance
|
||||
* - onUpdate:modelValue: The update handler for v-model
|
||||
*/
|
||||
export type ComponentWidgetCustomProps = Record<string, unknown>
|
||||
type ComponentWidgetCustomProps = Record<string, unknown>
|
||||
|
||||
/**
|
||||
* Standard props that are handled separately by DomWidget.vue and should be
|
||||
@@ -375,17 +375,3 @@ LGraphNode.prototype.addDOMWidget = function <
|
||||
|
||||
return widget
|
||||
}
|
||||
|
||||
/**
|
||||
* Prunes widgets that are no longer in the graph.
|
||||
* @param nodes The nodes to prune widgets for.
|
||||
*/
|
||||
export const pruneWidgets = (nodes: LGraphNode[]) => {
|
||||
const nodeSet = new Set(nodes)
|
||||
const domWidgetStore = useDomWidgetStore()
|
||||
for (const { widget } of domWidgetStore.widgetStates.values()) {
|
||||
if (!nodeSet.has(widget.node)) {
|
||||
domWidgetStore.unregisterWidget(widget.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useChainCallback } from '@/composables/functional/useChainCallback'
|
||||
import { useBooleanWidget } from '@/composables/widgets/useBooleanWidget'
|
||||
import { useFloatWidget } from '@/composables/widgets/useFloatWidget'
|
||||
import { useStringWidget } from '@/composables/widgets/useStringWidget'
|
||||
import { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import { useBooleanWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useBooleanWidget'
|
||||
import { useFloatWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useFloatWidget'
|
||||
import { useStringWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useStringWidget'
|
||||
|
||||
const StringWidget = useStringWidget()
|
||||
const FloatWidget = useFloatWidget()
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
type AvifIinfBox,
|
||||
type AvifIlocBox,
|
||||
type AvifInfeBox,
|
||||
ComfyMetadata,
|
||||
type ComfyMetadata,
|
||||
ComfyMetadataTags,
|
||||
type IsobmffBoxContentRange
|
||||
} from '@/types/metadataTypes'
|
||||
@@ -319,7 +319,7 @@ function parseAvifMetadata(buffer: ArrayBuffer): ComfyMetadata {
|
||||
}
|
||||
|
||||
// @ts-expect-error fixme ts strict error
|
||||
export function parseExifData(exifData) {
|
||||
function parseExifData(exifData) {
|
||||
// Check for the correct TIFF header (0x4949 for little-endian or 0x4D4D for big-endian)
|
||||
const isLittleEndian = String.fromCharCode(...exifData.slice(0, 2)) === 'II'
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {
|
||||
type ComfyApiWorkflow,
|
||||
type ComfyWorkflowJSON
|
||||
} from '@/schemas/comfyWorkflowSchema'
|
||||
} from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import {
|
||||
ComfyMetadata,
|
||||
type ComfyMetadata,
|
||||
ComfyMetadataTags,
|
||||
EbmlElementRange,
|
||||
EbmlTagPosition,
|
||||
TextRange,
|
||||
VInt
|
||||
type EbmlElementRange,
|
||||
type EbmlTagPosition,
|
||||
type TextRange,
|
||||
type VInt
|
||||
} from '@/types/metadataTypes'
|
||||
|
||||
const WEBM_SIGNATURE = [0x1a, 0x45, 0xdf, 0xa3]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** @knipIgnoreUnusedButUsedByCustomNodes */
|
||||
export function getFromFlacBuffer(buffer: ArrayBuffer): Record<string, string> {
|
||||
const dataView = new DataView(buffer)
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {
|
||||
ComfyApiWorkflow,
|
||||
ComfyWorkflowJSON
|
||||
} from '@/schemas/comfyWorkflowSchema'
|
||||
type ComfyApiWorkflow,
|
||||
type ComfyWorkflowJSON
|
||||
} from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import {
|
||||
ASCII,
|
||||
ComfyMetadata,
|
||||
type ComfyMetadata,
|
||||
ComfyMetadataTags,
|
||||
GltfChunkHeader,
|
||||
GltfHeader,
|
||||
GltfJsonData,
|
||||
type GltfChunkHeader,
|
||||
type GltfHeader,
|
||||
type GltfJsonData,
|
||||
GltfSizeBytes
|
||||
} from '@/types/metadataTypes'
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {
|
||||
ComfyApiWorkflow,
|
||||
ComfyWorkflowJSON
|
||||
} from '@/schemas/comfyWorkflowSchema'
|
||||
type ComfyApiWorkflow,
|
||||
type ComfyWorkflowJSON
|
||||
} from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
import {
|
||||
ASCII,
|
||||
ComfyMetadata,
|
||||
type ComfyMetadata,
|
||||
ComfyMetadataTags,
|
||||
IsobmffBoxContentRange
|
||||
type IsobmffBoxContentRange
|
||||
} from '@/types/metadataTypes'
|
||||
|
||||
// Set max read high, as atoms are stored near end of file
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/** @knipIgnoreUnusedButUsedByCustomNodes */
|
||||
export function getFromPngBuffer(buffer: ArrayBuffer) {
|
||||
// Get the PNG data as a Uint8Array
|
||||
const pngData = new Uint8Array(buffer)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ComfyMetadata } from '@/types/metadataTypes'
|
||||
import { type ComfyMetadata } from '@/types/metadataTypes'
|
||||
|
||||
export async function getSvgMetadata(file: File): Promise<ComfyMetadata> {
|
||||
const text = await file.text()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { WORKFLOW_ACCEPT_STRING } from '@/constants/supportedWorkflowFormats'
|
||||
import { type StatusWsMessageStatus, TaskItem } from '@/schemas/apiSchema'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { WORKFLOW_ACCEPT_STRING } from '@/platform/workflow/core/types/formats'
|
||||
import { type StatusWsMessageStatus, type TaskItem } from '@/schemas/apiSchema'
|
||||
import { useDialogService } from '@/services/dialogService'
|
||||
import { useLitegraphService } from '@/services/litegraphService'
|
||||
import { useCommandStore } from '@/stores/commandStore'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
|
||||
import { api } from './api'
|
||||
@@ -640,7 +640,6 @@ export class ComfyUI {
|
||||
confirm('Clear workflow?')
|
||||
) {
|
||||
app.clean()
|
||||
app.graph.clear()
|
||||
useLitegraphService().resetView()
|
||||
api.dispatchCustomEvent('graphCleared')
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Settings } from '@/schemas/apiSchema'
|
||||
import { type Settings } from '@/schemas/apiSchema'
|
||||
import type { ComfyApp } from '@/scripts/app'
|
||||
|
||||
import type { ComfyComponent } from '.'
|
||||
import { $el } from '../../ui'
|
||||
import { prop } from '../../utils'
|
||||
import { ClassList, applyClasses, toggleElement } from '../utils'
|
||||
import { type ClassList, applyClasses, toggleElement } from '../utils'
|
||||
import type { ComfyPopup } from './popup'
|
||||
|
||||
type ComfyButtonProps = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { $el } from '../../ui'
|
||||
import { prop } from '../../utils'
|
||||
import { ClassList, applyClasses } from '../utils'
|
||||
import { type ClassList, applyClasses } from '../utils'
|
||||
|
||||
export class ComfyPopup extends EventTarget {
|
||||
element = $el('div.comfyui-popup')
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { t } from '@/i18n'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import type { SettingParams } from '@/platform/settings/types'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
import type { Settings } from '@/schemas/apiSchema'
|
||||
import type { ComfyApp } from '@/scripts/app'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
import { useToastStore } from '@/stores/toastStore'
|
||||
import type { SettingParams } from '@/types/settingTypes'
|
||||
|
||||
import { ComfyDialog } from './dialog'
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ export function clone<T>(obj: T): T {
|
||||
}
|
||||
|
||||
/**
|
||||
* @knipIgnoreUnusedButUsedByCustomNodes
|
||||
* @deprecated Use `applyTextReplacements` from `@/utils/searchAndReplace` instead
|
||||
* There are external callers to this function, so we need to keep it for now
|
||||
*/
|
||||
@@ -24,6 +25,7 @@ export function applyTextReplacements(app: ComfyApp, value: string): string {
|
||||
return _applyTextReplacements(app.graph, value)
|
||||
}
|
||||
|
||||
/** @knipIgnoreUnusedButUsedByCustomNodes */
|
||||
export async function addStylesheet(
|
||||
urlOrFile: string,
|
||||
relativeTo?: string
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import { useBooleanWidget } from '@/composables/widgets/useBooleanWidget'
|
||||
import { useComboWidget } from '@/composables/widgets/useComboWidget'
|
||||
import { useFloatWidget } from '@/composables/widgets/useFloatWidget'
|
||||
import { useImageUploadWidget } from '@/composables/widgets/useImageUploadWidget'
|
||||
import { useIntWidget } from '@/composables/widgets/useIntWidget'
|
||||
import { useMarkdownWidget } from '@/composables/widgets/useMarkdownWidget'
|
||||
import { useStringWidget } from '@/composables/widgets/useStringWidget'
|
||||
import '@/core/graph/subgraph/proxyWidget'
|
||||
import { t } from '@/i18n'
|
||||
import { type LGraphNode, isComboWidget } from '@/lib/litegraph/src/litegraph'
|
||||
import type {
|
||||
@@ -12,10 +6,26 @@ import type {
|
||||
IComboWidget,
|
||||
IStringWidget
|
||||
} from '@/lib/litegraph/src/types/widgets'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useBooleanWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useBooleanWidget'
|
||||
import { useChartWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useChartWidget'
|
||||
import { useColorWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useColorWidget'
|
||||
import { useComboWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useComboWidget'
|
||||
import { useFileUploadWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useFileUploadWidget'
|
||||
import { useFloatWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useFloatWidget'
|
||||
import { useGalleriaWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useGalleriaWidget'
|
||||
import { useImageCompareWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useImageCompareWidget'
|
||||
import { useImageUploadWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useImageUploadWidget'
|
||||
import { useIntWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useIntWidget'
|
||||
import { useMarkdownWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useMarkdownWidget'
|
||||
import { useMultiSelectWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useMultiSelectWidget'
|
||||
import { useSelectButtonWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useSelectButtonWidget'
|
||||
import { useStringWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useStringWidget'
|
||||
import { useTextareaWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useTextareaWidget'
|
||||
import { useTreeSelectWidget } from '@/renderer/extensions/vueNodes/widgets/composables/useTreeSelectWidget'
|
||||
import { transformInputSpecV1ToV2 } from '@/schemas/nodeDef/migration'
|
||||
import type { InputSpec as InputSpecV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { InputSpec } from '@/schemas/nodeDefSchema'
|
||||
import { useSettingStore } from '@/stores/settingStore'
|
||||
|
||||
import type { ComfyApp } from './app'
|
||||
import './domWidget'
|
||||
@@ -130,7 +140,6 @@ export function addValueControlWidgets(
|
||||
|
||||
valueControl.tooltip =
|
||||
'Allows the linked widget to be changed automatically, for example randomizing the noise seed.'
|
||||
// @ts-ignore index with symbol
|
||||
valueControl[IS_CONTROL_WIDGET] = true
|
||||
updateControlWidgetLabel(valueControl)
|
||||
const widgets: [IComboWidget, ...IStringWidget[]] = [valueControl]
|
||||
@@ -263,12 +272,10 @@ export function addValueControlWidgets(
|
||||
valueControl.beforeQueued = () => {
|
||||
if (controlValueRunBefore()) {
|
||||
// Don't run on first execution
|
||||
// @ts-ignore index with symbol
|
||||
if (valueControl[HAS_EXECUTED]) {
|
||||
applyWidgetControl()
|
||||
}
|
||||
}
|
||||
// @ts-ignore index with symbol
|
||||
valueControl[HAS_EXECUTED] = true
|
||||
}
|
||||
|
||||
@@ -288,5 +295,14 @@ export const ComfyWidgets: Record<string, ComfyWidgetConstructor> = {
|
||||
STRING: transformWidgetConstructorV2ToV1(useStringWidget()),
|
||||
MARKDOWN: transformWidgetConstructorV2ToV1(useMarkdownWidget()),
|
||||
COMBO: transformWidgetConstructorV2ToV1(useComboWidget()),
|
||||
IMAGEUPLOAD: useImageUploadWidget()
|
||||
IMAGEUPLOAD: useImageUploadWidget(),
|
||||
FILEUPLOAD: transformWidgetConstructorV2ToV1(useFileUploadWidget()),
|
||||
COLOR: transformWidgetConstructorV2ToV1(useColorWidget()),
|
||||
IMAGECOMPARE: transformWidgetConstructorV2ToV1(useImageCompareWidget()),
|
||||
TREESELECT: transformWidgetConstructorV2ToV1(useTreeSelectWidget()),
|
||||
MULTISELECT: transformWidgetConstructorV2ToV1(useMultiSelectWidget()),
|
||||
CHART: transformWidgetConstructorV2ToV1(useChartWidget()),
|
||||
GALLERIA: transformWidgetConstructorV2ToV1(useGalleriaWidget()),
|
||||
SELECTBUTTON: transformWidgetConstructorV2ToV1(useSelectButtonWidget()),
|
||||
TEXTAREA: transformWidgetConstructorV2ToV1(useTextareaWidget())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user