mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-10 10:00:08 +00:00
refactor: move renderer-dependent utils into workbench scope (#6621)
This PR cleans up the base-layer utilities so they no longer pull renderer or workbench code. The renderer-only `isPrimitiveNode` guard now lives in `src/renderer/utils/nodeTypeGuards.ts`, and the node help/model/ordering helpers have moved into `src/workbench/utils`. All affected services, stores, scripts, and tests were updated to import from the new locations. The idea is to reduce the number of Base→Renderer/Base→Workbench edges (higher scoped base/common utils should not import from renderer/workbench layers). ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6621-refactor-move-renderer-dependent-utils-into-workbench-scope-2a36d73d36508167aff0fc8a22202d7f) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
import type { ModelFile } from '@/platform/workflow/validation/schemas/workflowSchema'
|
||||
|
||||
/**
|
||||
* Gets models from the node's `properties.models` field, excluding those
|
||||
* not currently selected in at least 1 of the node's widget values.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const node = {
|
||||
* type: 'CheckpointLoaderSimple',
|
||||
* widgets_values: ['model1', 'model2'],
|
||||
* properties: { models: [{ name: 'model1' }, { name: 'model2' }, { name: 'model3' }] }
|
||||
* ... other properties
|
||||
* }
|
||||
* const selectedModels = getSelectedModelsMetadata(node)
|
||||
* // selectedModels = [{ name: 'model1' }, { name: 'model2' }]
|
||||
* ```
|
||||
*
|
||||
* @param node - The workflow node to process
|
||||
* @returns Filtered array containing only models that are currently selected
|
||||
*/
|
||||
export function getSelectedModelsMetadata(node: {
|
||||
type: string
|
||||
widgets_values?: unknown[] | Record<string, unknown>
|
||||
properties?: { models?: ModelFile[] }
|
||||
}): ModelFile[] | undefined {
|
||||
try {
|
||||
if (!node.properties?.models?.length) return
|
||||
if (!node.widgets_values) return
|
||||
|
||||
const widgetValues = Array.isArray(node.widgets_values)
|
||||
? node.widgets_values
|
||||
: Object.values(node.widgets_values)
|
||||
|
||||
if (!widgetValues.length) return
|
||||
|
||||
const stringWidgetValues = new Set<string>()
|
||||
for (const widgetValue of widgetValues) {
|
||||
if (typeof widgetValue === 'string' && widgetValue.trim()) {
|
||||
stringWidgetValues.add(widgetValue)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the node's models that are present in the widget values
|
||||
return node.properties.models.filter((model) =>
|
||||
stringWidgetValues.has(model.name)
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Error filtering models by current selection:', error)
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
import type { TWidgetValue } from '@/lib/litegraph/src/litegraph'
|
||||
import type { InputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
|
||||
|
||||
/**
|
||||
* Gets an ordered array of InputSpec objects based on input_order.
|
||||
* This is designed to work with V2 format used by litegraphService.
|
||||
*
|
||||
* @param nodeDefImpl - The ComfyNodeDefImpl containing both V1 and V2 formats
|
||||
* @param inputs - The V2 format inputs (flat Record<string, InputSpec>)
|
||||
* @returns Array of InputSpec objects in the correct order
|
||||
*/
|
||||
export function getOrderedInputSpecs(
|
||||
nodeDefImpl: ComfyNodeDefImpl,
|
||||
inputs: Record<string, InputSpec>
|
||||
): InputSpec[] {
|
||||
const orderedInputSpecs: InputSpec[] = []
|
||||
|
||||
// If no input_order, return default Object.values order
|
||||
if (!nodeDefImpl.input_order) {
|
||||
return Object.values(inputs)
|
||||
}
|
||||
|
||||
// Process required inputs in specified order
|
||||
if (nodeDefImpl.input_order.required) {
|
||||
for (const name of nodeDefImpl.input_order.required) {
|
||||
const inputSpec = inputs[name]
|
||||
if (inputSpec && !inputSpec.isOptional) {
|
||||
orderedInputSpecs.push(inputSpec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Process optional inputs in specified order
|
||||
if (nodeDefImpl.input_order.optional) {
|
||||
for (const name of nodeDefImpl.input_order.optional) {
|
||||
const inputSpec = inputs[name]
|
||||
if (inputSpec && inputSpec.isOptional) {
|
||||
orderedInputSpecs.push(inputSpec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add any remaining inputs not specified in input_order
|
||||
const processedNames = new Set(orderedInputSpecs.map((spec) => spec.name))
|
||||
for (const inputSpec of Object.values(inputs)) {
|
||||
if (!processedNames.has(inputSpec.name)) {
|
||||
orderedInputSpecs.push(inputSpec)
|
||||
}
|
||||
}
|
||||
|
||||
return orderedInputSpecs
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorders widget values based on the input_order to match expected widget order.
|
||||
* This is used when widgets were created in a different order than input_order specifies.
|
||||
*
|
||||
* @param widgetValues - The current widget values array
|
||||
* @param currentWidgetOrder - The current order of widget names
|
||||
* @param inputOrder - The desired order from input_order
|
||||
* @returns Reordered widget values array
|
||||
*/
|
||||
export function sortWidgetValuesByInputOrder(
|
||||
widgetValues: TWidgetValue[],
|
||||
currentWidgetOrder: string[],
|
||||
inputOrder: string[]
|
||||
): TWidgetValue[] {
|
||||
if (!inputOrder || inputOrder.length === 0) {
|
||||
return widgetValues
|
||||
}
|
||||
|
||||
// Create a map of widget name to value
|
||||
const valueMap = new Map<string, TWidgetValue>()
|
||||
currentWidgetOrder.forEach((name, index) => {
|
||||
if (index < widgetValues.length) {
|
||||
valueMap.set(name, widgetValues[index])
|
||||
}
|
||||
})
|
||||
|
||||
// Reorder based on input_order
|
||||
const reordered: TWidgetValue[] = []
|
||||
const usedNames = new Set<string>()
|
||||
|
||||
// First, add values in the order specified by input_order
|
||||
for (const name of inputOrder) {
|
||||
if (valueMap.has(name)) {
|
||||
reordered.push(valueMap.get(name))
|
||||
usedNames.add(name)
|
||||
}
|
||||
}
|
||||
|
||||
// Then add any remaining values not in input_order
|
||||
for (const [name, value] of valueMap.entries()) {
|
||||
if (!usedNames.has(name)) {
|
||||
reordered.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
// If there are extra values not in the map, append them
|
||||
if (widgetValues.length > currentWidgetOrder.length) {
|
||||
for (let i = currentWidgetOrder.length; i < widgetValues.length; i++) {
|
||||
reordered.push(widgetValues[i])
|
||||
}
|
||||
}
|
||||
|
||||
return reordered
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import type { ComfyNodeDefImpl } from '@/stores/nodeDefStore'
|
||||
import { NodeSourceType, getNodeSource } from '@/types/nodeSource'
|
||||
import { normalizePackId } from '@/utils/packUtils'
|
||||
|
||||
export function extractCustomNodeName(
|
||||
pythonModule: string | undefined
|
||||
): string | null {
|
||||
const modules = pythonModule?.split('.') || []
|
||||
if (modules.length >= 2 && modules[0] === 'custom_nodes') {
|
||||
// Use normalizePackId to remove version suffix
|
||||
return normalizePackId(modules[1])
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function getNodeHelpBaseUrl(node: ComfyNodeDefImpl): string {
|
||||
const nodeSource = getNodeSource(node.python_module)
|
||||
if (nodeSource.type === NodeSourceType.CustomNodes) {
|
||||
const customNodeName = extractCustomNodeName(node.python_module)
|
||||
if (customNodeName) {
|
||||
return `/extensions/${customNodeName}/docs/`
|
||||
}
|
||||
}
|
||||
return `/docs/${node.name}/`
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { PrimitiveNode } from '@/extensions/core/widgetInputs'
|
||||
import type {
|
||||
INodeSlot,
|
||||
LGraph,
|
||||
@@ -6,12 +5,6 @@ import type {
|
||||
Subgraph
|
||||
} from '@/lib/litegraph/src/litegraph'
|
||||
|
||||
export function isPrimitiveNode(
|
||||
node: LGraphNode
|
||||
): node is PrimitiveNode & LGraphNode {
|
||||
return node.type === 'PrimitiveNode'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an error is an AbortError triggered by `AbortController#abort`
|
||||
* when cancelling a request.
|
||||
|
||||
Reference in New Issue
Block a user