mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-06-08 15:29:52 +00:00
## Summary
Move the canonical `UUID` utilities and the `NodeId` alias up out of
`src/lib/litegraph/` so non-litegraph code can reference them without
crossing the litegraph layer boundary.
## Changes
- **What**:
- `src/lib/litegraph/src/utils/uuid.ts` → `src/utils/uuid.ts` (full
file: `UUID`, `zeroUuid`, `createUuidv4`).
- `NodeId` moves from `src/lib/litegraph/src/LGraphNode.ts` to
`src/world/entityIds.ts`. `LGraphNode.ts` re-exports it; the litegraph
barrel still re-exports `createUuidv4` / `UUID` so the package's public
surface is unchanged.
- All 22 importers updated to `@/utils/uuid` (both
`@/lib/litegraph/src/utils/uuid` and the litegraph-internal
`./utils/uuid` relative paths).
- Drops the two `import-x/no-restricted-paths` ESLint disables in
`src/world/entityIds.ts` that were waiting on these moves.
- **Breaking**: None — litegraph re-exports preserve backward
compatibility for downstream consumers.
## Review Focus
- Each importer's change is identical (`@/lib/litegraph/src/utils/uuid`
→ `@/utils/uuid`), generated by `sed`.
- `src/lib/litegraph/src/LGraphNode.ts` now does `import type { NodeId }
from '@/world/entityIds'` + `export type { NodeId }` — confirm this
satisfies the litegraph layer boundary rules.
- `src/world/entityIds.ts` defines `NodeId` locally as `number |
string`; no semantic change.
Co-authored-by: Amp <amp@ampcode.com>
142 lines
4.6 KiB
TypeScript
142 lines
4.6 KiB
TypeScript
import type { MaybeRefOrGetter } from 'vue'
|
|
import { computed, toValue } from 'vue'
|
|
|
|
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
|
|
import { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode'
|
|
import type { UUID } from '@/utils/uuid'
|
|
import { useNodeOutputStore } from '@/stores/nodeOutputStore'
|
|
import { usePreviewExposureStore } from '@/stores/previewExposureStore'
|
|
import { createNodeLocatorId } from '@/types/nodeIdentification'
|
|
|
|
interface PromotedPreview {
|
|
sourceNodeId: string
|
|
sourceWidgetName: string
|
|
type: 'image' | 'video' | 'audio'
|
|
urls: string[]
|
|
}
|
|
|
|
const PREVIEW_TYPES_BY_MEDIA = {
|
|
video: 'video',
|
|
audio: 'audio'
|
|
} as const satisfies Partial<Record<string, PromotedPreview['type']>>
|
|
|
|
function getPreviewMediaType(node: LGraphNode): PromotedPreview['type'] {
|
|
const media = node.previewMediaType
|
|
if (media && media in PREVIEW_TYPES_BY_MEDIA) {
|
|
return PREVIEW_TYPES_BY_MEDIA[media as keyof typeof PREVIEW_TYPES_BY_MEDIA]
|
|
}
|
|
return 'image'
|
|
}
|
|
|
|
export function usePromotedPreviews(
|
|
lgraphNode: MaybeRefOrGetter<LGraphNode | null | undefined>
|
|
) {
|
|
const previewExposureStore = usePreviewExposureStore()
|
|
const nodeOutputStore = useNodeOutputStore()
|
|
|
|
/** Touches reactive sources for Vue tracking; `getNodeImageUrls` reads non-reactive app state. */
|
|
function readReactivePreviewUrls(
|
|
leafHost: SubgraphNode,
|
|
leafSourceNodeId: string,
|
|
leafExecutionId: string,
|
|
interiorNode: LGraphNode
|
|
): string[] | undefined {
|
|
const locatorId = createNodeLocatorId(
|
|
leafHost.subgraph.id,
|
|
leafSourceNodeId
|
|
)
|
|
const reactiveOutputs = nodeOutputStore.nodeOutputs[locatorId]
|
|
const reactivePreviews = nodeOutputStore.nodePreviewImages[locatorId]
|
|
const reactiveExecutionOutputs =
|
|
nodeOutputStore.getNodeOutputByExecutionId(leafExecutionId)
|
|
const reactiveExecutionPreviews =
|
|
nodeOutputStore.getNodePreviewImagesByExecutionId(leafExecutionId)
|
|
const hasAnySource =
|
|
reactiveOutputs?.images?.length ||
|
|
reactivePreviews?.length ||
|
|
reactiveExecutionOutputs?.images?.length ||
|
|
reactiveExecutionPreviews?.length
|
|
if (!hasAnySource) return undefined
|
|
return (
|
|
nodeOutputStore.getNodeImageUrlsByExecutionId(
|
|
leafExecutionId,
|
|
interiorNode
|
|
) ?? nodeOutputStore.getNodeImageUrls(interiorNode)
|
|
)
|
|
}
|
|
|
|
const promotedPreviews = computed((): PromotedPreview[] => {
|
|
const node = toValue(lgraphNode)
|
|
if (!(node instanceof SubgraphNode)) return []
|
|
|
|
const rootGraphId = node.rootGraph.id
|
|
const hostLocator = String(node.id)
|
|
const exposures = previewExposureStore.getExposures(
|
|
rootGraphId,
|
|
hostLocator
|
|
)
|
|
if (!exposures.length) return []
|
|
|
|
const hostNodesByLocator = new Map<string, SubgraphNode>([
|
|
[hostLocator, node]
|
|
])
|
|
|
|
function resolveNestedHost(
|
|
rootGraphId: UUID,
|
|
currentHostLocator: string,
|
|
sourceNodeId: string
|
|
) {
|
|
const currentHost = hostNodesByLocator.get(currentHostLocator)
|
|
const sourceNode = currentHost?.subgraph.getNodeById(sourceNodeId)
|
|
if (!(sourceNode instanceof SubgraphNode)) return undefined
|
|
|
|
const pathLocator = `${currentHostLocator}:${sourceNode.id}`
|
|
const definitionLocator = String(sourceNode.id)
|
|
const hasPathExposures =
|
|
previewExposureStore.getExposures(rootGraphId, pathLocator).length > 0
|
|
const nestedHostLocator = hasPathExposures
|
|
? pathLocator
|
|
: definitionLocator
|
|
hostNodesByLocator.set(nestedHostLocator, sourceNode)
|
|
return { rootGraphId, hostNodeLocator: nestedHostLocator }
|
|
}
|
|
|
|
return exposures.flatMap((exposure): PromotedPreview[] => {
|
|
const resolved = previewExposureStore.resolveChain(
|
|
rootGraphId,
|
|
hostLocator,
|
|
exposure.name,
|
|
resolveNestedHost
|
|
)
|
|
const leaf = resolved?.leaf ?? {
|
|
sourceNodeId: exposure.sourceNodeId,
|
|
sourcePreviewName: exposure.sourcePreviewName
|
|
}
|
|
const leafHostLocator =
|
|
resolved?.steps.at(-1)?.hostNodeLocator ?? hostLocator
|
|
const leafHost = hostNodesByLocator.get(leafHostLocator) ?? node
|
|
const interiorNode = leafHost.subgraph.getNodeById(leaf.sourceNodeId)
|
|
if (!interiorNode) return []
|
|
|
|
const urls = readReactivePreviewUrls(
|
|
leafHost,
|
|
leaf.sourceNodeId,
|
|
`${leafHostLocator}:${leaf.sourceNodeId}`,
|
|
interiorNode
|
|
)
|
|
if (!urls?.length) return []
|
|
|
|
return [
|
|
{
|
|
sourceNodeId: leaf.sourceNodeId,
|
|
sourceWidgetName: leaf.sourcePreviewName,
|
|
type: getPreviewMediaType(interiorNode),
|
|
urls
|
|
}
|
|
]
|
|
})
|
|
})
|
|
|
|
return { promotedPreviews }
|
|
}
|