mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-01 22:09:55 +00:00
Add graph ID creation / serialisation (#790)
- Updates UUIDv4 generator - Adds a unique id & revision support to graphs - `revision` to be incremented downstream (e.g. on save) - `id` automatically assigned if not provided
This commit is contained in:
@@ -14,6 +14,9 @@ import type {
|
||||
SerialisableGraph,
|
||||
SerialisableReroute,
|
||||
} from "./types/serialisation"
|
||||
import type { UUID } from "@/utils/uuid"
|
||||
|
||||
import { createUuidv4, zeroUuid } from "@/utils/uuid"
|
||||
|
||||
import { LGraphCanvas } from "./LGraphCanvas"
|
||||
import { LGraphGroup } from "./LGraphGroup"
|
||||
@@ -66,6 +69,9 @@ export class LGraph implements LinkNetwork, Serialisable<SerialisableGraph> {
|
||||
static STATUS_STOPPED = 1
|
||||
static STATUS_RUNNING = 2
|
||||
|
||||
id: UUID = zeroUuid
|
||||
revision: number = 0
|
||||
|
||||
_version: number = -1
|
||||
/** The backing store for links. Keys are wrapped in String() */
|
||||
_links: Map<LinkId, LLink> = new Map()
|
||||
@@ -1513,6 +1519,8 @@ export class LGraph implements LinkNetwork, Serialisable<SerialisableGraph> {
|
||||
|
||||
extra.reroutes = reroutes?.length ? reroutes : undefined
|
||||
return {
|
||||
id: this.id,
|
||||
revision: this.revision,
|
||||
last_node_id: state.lastNodeId,
|
||||
last_link_id: state.lastLinkId,
|
||||
nodes,
|
||||
@@ -1534,7 +1542,7 @@ export class LGraph implements LinkNetwork, Serialisable<SerialisableGraph> {
|
||||
* It is intended for use with {@link structuredClone} or {@link JSON.stringify}.
|
||||
*/
|
||||
asSerialisable(options?: { sortNodes: boolean }): SerialisableGraph & Required<Pick<SerialisableGraph, "nodes" | "groups" | "extra">> {
|
||||
const { config, state, extra } = this
|
||||
const { id, revision, config, state, extra } = this
|
||||
|
||||
const nodeList = !LiteGraph.use_uuids && options?.sortNodes
|
||||
// @ts-expect-error If LiteGraph.use_uuids is false, ids are numbers.
|
||||
@@ -1549,6 +1557,8 @@ export class LGraph implements LinkNetwork, Serialisable<SerialisableGraph> {
|
||||
const reroutes = this.reroutes.size ? [...this.reroutes.values()].map(x => x.asSerialisable()) : undefined
|
||||
|
||||
const data: ReturnType<typeof this.asSerialisable> = {
|
||||
id,
|
||||
revision,
|
||||
version: LGraph.serialisedSchemaVersion,
|
||||
config,
|
||||
state,
|
||||
@@ -1578,6 +1588,10 @@ export class LGraph implements LinkNetwork, Serialisable<SerialisableGraph> {
|
||||
if (!data) return
|
||||
if (!keep_old) this.clear()
|
||||
|
||||
// Create a new graph ID if none is provided
|
||||
if (data.id) this.id = data.id
|
||||
else if (this.id === zeroUuid) this.id = createUuidv4()
|
||||
|
||||
let reroutes: SerialisableReroute[] | undefined
|
||||
|
||||
// TODO: Determine whether this should this fall back to 0.4.
|
||||
@@ -1665,7 +1679,7 @@ export class LGraph implements LinkNetwork, Serialisable<SerialisableGraph> {
|
||||
// copy all stored fields
|
||||
for (const i in data) {
|
||||
// links must be accepted
|
||||
if (["nodes", "groups", "links", "state", "reroutes", "floatingLinks"].includes(i)) {
|
||||
if (["nodes", "groups", "links", "state", "reroutes", "floatingLinks", "id"].includes(i)) {
|
||||
continue
|
||||
}
|
||||
// @ts-expect-error #574 Legacy property assignment
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
RenderShape,
|
||||
TitleMode,
|
||||
} from "./types/globalEnums"
|
||||
import { createUuidv4 } from "./utils/uuid"
|
||||
|
||||
/**
|
||||
* The Global Scope. It contains all the registered node classes.
|
||||
@@ -549,14 +550,8 @@ export class LiteGraphGlobal {
|
||||
return target
|
||||
}
|
||||
|
||||
/*
|
||||
* https://gist.github.com/jed/982883?permalink_comment_id=852670#gistcomment-852670
|
||||
*/
|
||||
uuidv4(): string {
|
||||
// @ts-expect-error
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replaceAll(/[018]/g, a =>
|
||||
(a ^ ((Math.random() * 16) >> (a / 4))).toString(16))
|
||||
}
|
||||
/** @see {@link createUuidv4} @inheritdoc */
|
||||
uuidv4 = createUuidv4
|
||||
|
||||
/**
|
||||
* Returns if the types of two slots are compatible (taking into account wildcards, etc)
|
||||
|
||||
@@ -15,6 +15,7 @@ import type { LinkId, SerialisedLLinkArray } from "../LLink"
|
||||
import type { FloatingRerouteSlot, RerouteId } from "../Reroute"
|
||||
import type { TWidgetValue } from "../types/widgets"
|
||||
import type { RenderShape } from "./globalEnums"
|
||||
import type { UUID } from "@/utils/uuid"
|
||||
|
||||
/**
|
||||
* An object that implements custom pre-serialization logic via {@link Serialisable.asSerialisable}.
|
||||
@@ -29,6 +30,9 @@ export interface Serialisable<SerialisableObject> {
|
||||
}
|
||||
|
||||
export interface SerialisableGraph {
|
||||
/** Unique graph ID. Automatically generated if not provided. */
|
||||
id: UUID
|
||||
revision: number
|
||||
/** Schema version. @remarks Version bump should add to const union, which is used to narrow type during deserialise. */
|
||||
version: 0 | 1
|
||||
config: LGraphConfig
|
||||
@@ -80,6 +84,8 @@ export interface ISerialisedNode {
|
||||
* Maintained for backwards compat
|
||||
*/
|
||||
export interface ISerialisedGraph {
|
||||
id: UUID
|
||||
revision: number
|
||||
last_node_id: NodeId
|
||||
last_link_id: number
|
||||
nodes: ISerialisedNode[]
|
||||
|
||||
29
src/utils/uuid.ts
Normal file
29
src/utils/uuid.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
export type UUID = `${string}-${string}-${string}-${string}-${string}`
|
||||
|
||||
/** Special-case zero-UUID, consisting entirely of zeros. Used as a default value. */
|
||||
export const zeroUuid = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
/** Pre-allocated storage for uuid random values. */
|
||||
const randomStorage = new Uint32Array(31)
|
||||
|
||||
/**
|
||||
* Creates a UUIDv4 string.
|
||||
* @returns A new UUIDv4 string
|
||||
* @remarks
|
||||
* Original implementation from https://gist.github.com/jed/982883?permalink_comment_id=852670#gistcomment-852670
|
||||
*
|
||||
* Prefers the {@link crypto.randomUUID} method if available, falling back to
|
||||
* {@link crypto.getRandomValues}, then finally the legacy {@link Math.random} method.
|
||||
*/
|
||||
export function createUuidv4(): UUID {
|
||||
if (typeof crypto?.randomUUID === "function") return crypto.randomUUID()
|
||||
// Assertion: `replaceAll` returns `string`; UUID format must be asserted below
|
||||
if (typeof crypto?.getRandomValues === "function") {
|
||||
const random = crypto.getRandomValues(randomStorage)
|
||||
let i = 0
|
||||
return "10000000-1000-4000-8000-100000000000".replaceAll(/[018]/g, a =>
|
||||
(Number(a) ^ ((random[i++] * 3.725_290_298_461_914e-9) >> (Number(a) * 0.25))).toString(16)) as UUID
|
||||
}
|
||||
return "10000000-1000-4000-8000-100000000000".replaceAll(/[018]/g, a =>
|
||||
(Number(a) ^ ((Math.random() * 16) >> (Number(a) * 0.25))).toString(16)) as UUID
|
||||
}
|
||||
@@ -240,6 +240,7 @@ LGraph {
|
||||
"fixedtime": 0,
|
||||
"fixedtime_lapse": 0.01,
|
||||
"globaltime": 0,
|
||||
"id": "ca9da7d8-fddd-4707-ad32-67be9be13140",
|
||||
"inputs": {},
|
||||
"iteration": 0,
|
||||
"last_update_time": 0,
|
||||
@@ -249,6 +250,7 @@ LGraph {
|
||||
"nodes_executedAction": [],
|
||||
"nodes_executing": [],
|
||||
"outputs": {},
|
||||
"revision": 0,
|
||||
"runningtime": 0,
|
||||
"starttime": 0,
|
||||
"state": {
|
||||
@@ -285,6 +287,7 @@ LGraph {
|
||||
"fixedtime": 0,
|
||||
"fixedtime_lapse": 0.01,
|
||||
"globaltime": 0,
|
||||
"id": "d175890f-716a-4ece-ba33-1d17a513b7be",
|
||||
"inputs": {},
|
||||
"iteration": 0,
|
||||
"last_update_time": 0,
|
||||
@@ -294,6 +297,7 @@ LGraph {
|
||||
"nodes_executedAction": [],
|
||||
"nodes_executing": [],
|
||||
"outputs": {},
|
||||
"revision": 0,
|
||||
"runningtime": 0,
|
||||
"starttime": 0,
|
||||
"state": {
|
||||
|
||||
@@ -246,6 +246,7 @@ LGraph {
|
||||
"fixedtime": 0,
|
||||
"fixedtime_lapse": 0.01,
|
||||
"globaltime": 0,
|
||||
"id": "b4e984f1-b421-4d24-b8b4-ff895793af13",
|
||||
"inputs": {},
|
||||
"iteration": 0,
|
||||
"last_update_time": 0,
|
||||
@@ -255,6 +256,7 @@ LGraph {
|
||||
"nodes_executedAction": [],
|
||||
"nodes_executing": [],
|
||||
"outputs": {},
|
||||
"revision": 0,
|
||||
"runningtime": 0,
|
||||
"starttime": 0,
|
||||
"state": {
|
||||
|
||||
@@ -240,6 +240,7 @@ LGraph {
|
||||
"fixedtime": 0,
|
||||
"fixedtime_lapse": 0.01,
|
||||
"globaltime": 0,
|
||||
"id": "ca9da7d8-fddd-4707-ad32-67be9be13140",
|
||||
"inputs": {},
|
||||
"iteration": 0,
|
||||
"last_update_time": 0,
|
||||
@@ -249,6 +250,7 @@ LGraph {
|
||||
"nodes_executedAction": [],
|
||||
"nodes_executing": [],
|
||||
"outputs": {},
|
||||
"revision": 0,
|
||||
"runningtime": 0,
|
||||
"starttime": 0,
|
||||
"state": {
|
||||
@@ -285,6 +287,7 @@ LGraph {
|
||||
"fixedtime": 0,
|
||||
"fixedtime_lapse": 0.01,
|
||||
"globaltime": 0,
|
||||
"id": "d175890f-716a-4ece-ba33-1d17a513b7be",
|
||||
"inputs": {},
|
||||
"iteration": 0,
|
||||
"last_update_time": 0,
|
||||
@@ -294,6 +297,7 @@ LGraph {
|
||||
"nodes_executedAction": [],
|
||||
"nodes_executing": [],
|
||||
"outputs": {},
|
||||
"revision": 0,
|
||||
"runningtime": 0,
|
||||
"starttime": 0,
|
||||
"state": {
|
||||
|
||||
@@ -179,5 +179,6 @@ LiteGraphGlobal {
|
||||
"throw_errors": true,
|
||||
"use_legacy_node_error_indicator": false,
|
||||
"use_uuids": false,
|
||||
"uuidv4": [Function],
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { ISerialisedGraph, SerialisableGraph } from "@/litegraph"
|
||||
|
||||
export const oldSchemaGraph: ISerialisedGraph = {
|
||||
id: "b4e984f1-b421-4d24-b8b4-ff895793af13",
|
||||
revision: 0,
|
||||
version: 0.4,
|
||||
config: {},
|
||||
last_node_id: 0,
|
||||
@@ -23,6 +25,8 @@ export const oldSchemaGraph: ISerialisedGraph = {
|
||||
}
|
||||
|
||||
export const minimalSerialisableGraph: SerialisableGraph = {
|
||||
id: "d175890f-716a-4ece-ba33-1d17a513b7be",
|
||||
revision: 0,
|
||||
version: 1,
|
||||
config: {},
|
||||
state: {
|
||||
@@ -37,6 +41,8 @@ export const minimalSerialisableGraph: SerialisableGraph = {
|
||||
}
|
||||
|
||||
export const basicSerialisableGraph: SerialisableGraph = {
|
||||
id: "ca9da7d8-fddd-4707-ad32-67be9be13140",
|
||||
revision: 0,
|
||||
version: 1,
|
||||
config: {},
|
||||
state: {
|
||||
|
||||
Reference in New Issue
Block a user